private void WorkerThread()
{
int samples = bufferSize / sizeof(float);
try
{
// The first write should fill the entire buffer.
var request = new NewFrameRequestedEventArgs(samples);
NewFrameRequested.Invoke(this, request);
buffer.Write(request.Buffer, 0, LockFlags.None);
// The buffer starts playing.
buffer.Play(0, PlayFlags.Looping);
int framesPlayed = request.FrameIndex;
int lastNotificationLocation = 0;
bool requestedToStop = false;
while (!stop)
{
int positionIndex = WaitHandle.WaitAny(waitHandles);
if (stop) break;
if (positionIndex == firstHalfBufferIndex ||
positionIndex == secondHalfBufferIndex)
{
if (requestedToStop) break;
// When the first half of the buffer has finished
// playing and we have just started playing the
// second half, we will write the next samples in
// the first half of the buffer again.
// When the second half of the buffer has finished
// playing, the first half of the buffer will
// start playing again (since this is a circular
// buffer). At this time, we can write the next
// samples in the second half of the buffer.
request.Frames = samples / 2;
NewFrameRequested(this, request);
requestedToStop = request.Stop;
int offset = (positionIndex == firstHalfBufferIndex) ? 0 : bufferSize / 2;
buffer.Write(request.Buffer, 0, request.Frames, offset, LockFlags.None);
}
if (positionIndex != secondHalfBufferIndex)
{
// Notify progress
int currentBufferLocation = notifications[positionIndex].Offset;
if (lastNotificationLocation >= currentBufferLocation)
lastNotificationLocation = -(bufferSize - lastNotificationLocation);
int delta = (currentBufferLocation - lastNotificationLocation);
framesPlayed += delta / sizeof(float);
lastNotificationLocation = currentBufferLocation;
OnFramePlayingStarted(new PlayFrameEventArgs(framesPlayed, delta));
}
}
}
catch (Exception ex)
{
if (AudioOutputError != null)
AudioOutputError(this, new AudioOutputErrorEventArgs(ex.Message));
else throw;
}
finally
{
buffer.Stop();
OnStopped(EventArgs.Empty);
}
}