Reputation: 5198
I am writing in C#.
I have a Real-Time audio player that plays incoming voice from IP Phone. I have a byte[] Array
which gets all the voice-bytes when it comes in, and when the user presses the PLAY button, I start playing it. I also have STOP and PAUSE buttons. I am using NAudio for this, BufferedWaveProvider and Waveout Classes.
CODE IN PLAYER CLASS:
public void PlayCall(Call call)
{
byte[] mixedBuffer = new byte[320];
while (call.PlayerIndex < call.AudioArray.Length) // The AudioArray keeps getting bigger
{
if (_state == PlayerState.PAUSED || _state == PlayerState.STOPPED)
// either STOP or PAUSE button is clicked
break;
for (int i = 0; i < 320; i++)
{
mixedBuffer[i] = (byte)(call.AudioArray[call.PlayerIndex + i];
}
call.PlayerIndex += 320;
Thread.Sleep(20); // This is in order to synchronize the receiving and playing of the packets.
try
{
AddSamples(mixedBuffer);
Waveout.Play();
}
catch (InvalidOperationException ex)
{
_bufferedWaveProvider.ClearBuffer();
}
finally
{
ClearByteArray(ref mixedBuffer);
}
}
}
public void StopCall(Call call)
{
_state = PalyerState.STOPPED;
call.PlayerIndex=0;
Waveout.Stop();
}
public void PauseCall(Call call)
{
_state = PlayerState.PAUSED;
Waveout.Pause();
}
the _state
is for the State of the call (PLAYING, STOPPED, PAUSED).
As you can see, When PLAY is pressed, It keeps playing until STOP/PAUSED is pressed, then it breaks. (the WHILE Loop).
My problem is after I press the buttons a little bit, at some point The Waveout.PLAY doesn't work anymore and therefore the BufferedWaveProvider
is getting full and crashes. (it happens sometime after two clicks, and sometimes after 10, changing).
I think it has something to do with the way I am calling the methods. Maybe some mix-up with Threads
/Tasks
, or not making sure one of the methods is over.. it's like this:
CODE ON THE VIEW-MODEL:
private void ExecutePlayCallMethod(Call call)
{
call.Player.State = PlayerState.PLAYING;
Task.Run(() => call.Player.PlayCall(call)); //
}
private void ExecutePauseCallMethod(CAll call)
{
Task.Run(() => call.Player.PauseCall(call));
call.Player.State = PlayerState.PAUSED;
}
private void ExecuteStopCallMethod(Call call)
{
call.Player.State = PlayerState.STOPPED;
Task.Run(() => call.Player.StopCall(call));
}
Help Please? I have been struggling with this for a long time..
Thanks in advance!
Upvotes: 1
Views: 173
Reputation: 16574
I suspect that calling Waveout.Play()
multiple times is the problem. You only need to call Play()
once, then feed samples into the source wave provider (your BufferedWaveProvider
instance) and the library will take care of the rest. When the wave provider is empty the WaveOut
object will continue to play silence until you provide more samples.
This can all be achieved in a single thread, incidentally. Create the WaveOut
instance, create a BufferedWaveProvider
as a sample buffer and set it running. Then when the audio data is available all you have to do is add the data to the BufferedWaveProvider
and it will be played.
The BufferedWaveProvider
uses a thread-safe internal buffer, so it's safe to add from a different thread if you feel that you really need to do so.
Upvotes: 1