Here is my code in Visual Basic that works well for me to determine when the playback is done. It uses a loop to keep testing WaveOut.PlaybackState
In the loop, you will notice that a short thread sleep of 50 is used to stop the cpu running away. I picked 50 from experience, you may find another value works better for you through trial and error.
And finally, the loop allows windows.forms events so the user can click the Stop button, with the statement:
System.Windows.Forms.Application.DoEvents
In the code I have supplied below, you can see events being raised - for example:
RaiseEvent Enable_PlayButton
I have defined events to allow a parent class to enable the Play, Stop, and Record buttons:
Public Event Enable_PlayButton(Enabled As Boolean)
Public Event Enable_StopButton(Enabled As Boolean)
Public Event Enable_RecordButton(Enabled As Boolean)
Public Event Enable_SaveButton(Enabled As Boolean)
Public Event Enable_RevertButton(Enabled As Boolean)
Public Event RecordingChanged(NewRecording As Byte())
In a parent class, I use AddHandler to wire these up to method in the parent class. In the following example, I have methods such as in the first case, "EnablePlay". Likewise for the other events.
AddHandler mMicrophoneRecorder.Enable_PlayButton, AddressOf EnablePlay
AddHandler mMicrophoneRecorder.Enable_StopButton, AddressOf EnableStop
AddHandler mMicrophoneRecorder.Enable_RecordButton, AddressOf EnableRecord
AddHandler mMicrophoneRecorder.Enable_RevertButton, AddressOf EnableRevert
AddHandler mMicrophoneRecorder.RecordingChanged, AddressOf MicRecorder_RecordingChanged
In this method, there are 3 fields that are defined elsewhere:
mWaveOut_via_SoundCard - a class-level (field) of WaveOut.
mAudioFile - instantiated here but held at the class level (a field).
mWavRecordingPath - the path to the audio (wav) file being played.
These 3 fields could probably be passed in to this method as parameters if you prefer to inject them. I used fields, because that's just the way my code for this evolved.
Here then, is the code:
Public Sub A_PlayClicked()
If mWaveOut_via_SoundCard Is Nothing Then
mWaveOut_via_SoundCard = New WaveOutEvent()
End If
If mAudioFile Is Nothing AndAlso mWavRecordingPath <> "" Then
mAudioFile = New AudioFileReader(mWavRecordingPath)
mWaveOut_via_SoundCard.Init(mAudioFile)
End If
RaiseEvent Enable_StopButton(True)
mWaveOut_via_SoundCard.Play()
Dim PlayDone As Boolean = False
Dim PState As PlaybackState
Do
'if stopped or finished, mSoundCard will be nothing,
'so we test that by trying to get PlayBackState
' from the WaveOut object (mSoundCard)
If mWaveOut_via_SoundCard Is Nothing Then
PlayDone = True
Else
Try
PState = mWaveOut_via_SoundCard.PlaybackState
Catch ex As Exception
'mSoundCard is probably nothing - but
'no matter what the problem, for now we will say
'that PlayDone is true.
PlayDone = True
End Try
End If
'Okay we got the PlayState, so evaluate and
'decide whether to continue here:
If Not PlayDone Then
If PState <> PlaybackState.Stopped Then
'let the system do stuff (e.g. user might click Stop button)
System.Windows.Forms.Application.DoEvents()
'don't use all the cpu:
Threading.Thread.Sleep(50)
Else
'well it's stopped so we're done:
PlayDone = True
End If
End If
Loop Until PlayDone = True
'here we could raiseevent stopped as well
RaiseEvent Enable_PlayButton(mCanPlay)
RaiseEvent Enable_RecordButton(True)
End Sub
PlaybackStopped
is not fired after the playback completed? Because from the source that the end ofprocessSamples()
in the finally it fires the event... – Maimonides