private void PlayAsync()
{
int currentPlayCounter = 0;
int nextBuffer = 0;
try
{
while (true)
{
// Check that this instanced is not disposed
while (!IsDisposed)
{
if (playEvent.WaitOne(WaitPrecision))
break;
}
if (IsDisposed)
break;
clock.Restart();
playPositionStart = nextPlayPosition;
playPosition = playPositionStart;
currentPlayCounter = playCounter;
// Get the decoded samples from the specified starting position.
var sampleIterator = audioDecoder.GetSamples(playPositionStart).GetEnumerator();
bool isFirstTime = true;
bool endOfSong = false;
crossfadeActive = false;
// Playing all the samples
while (true)
{
// If the player is stopped or disposed, then break of this loop
while (!IsDisposed && State != AudioPlayerState.Stopped)
{
if (playEvent.WaitOne(WaitPrecision))
break;
}
// If the player is stopped or disposed, then break of this loop
if (IsDisposed || State == AudioPlayerState.Stopped)
{
nextPlayPosition = TimeSpan.Zero;
break;
}
// If there was a change in the play position, restart the sample iterator.
if (currentPlayCounter != playCounter)
break;
// If ring buffer queued is full, wait for the end of a buffer.
while (sourceVoice.State.BuffersQueued == audioBuffersRing.Length && !IsDisposed && State != AudioPlayerState.Stopped)
bufferEndEvent.WaitOne(WaitPrecision);
// If the player is stopped or disposed, then break of this loop
if (IsDisposed || State == AudioPlayerState.Stopped)
{
nextPlayPosition = TimeSpan.Zero;
break;
}
// Check that there is a next sample
if (!sampleIterator.MoveNext())
{
endOfSong = true;
break;
}
// Retrieve a pointer to the sample data
var bufferPointer = sampleIterator.Current;
// If there was a change in the play position, restart the sample iterator.
if (currentPlayCounter != playCounter)
break;
// Check that our ring buffer has enough space to store the audio buffer.
if (bufferPointer.Size > memBuffers[nextBuffer].Size)
{
if (memBuffers[nextBuffer].Pointer != IntPtr.Zero)
Utilities.FreeMemory(memBuffers[nextBuffer].Pointer);
memBuffers[nextBuffer].Pointer = Utilities.AllocateMemory(bufferPointer.Size);
memBuffers[nextBuffer].Size = bufferPointer.Size;
}
// Copy the memory from MediaFoundation AudioDecoder to the buffer that is going to be played.
Utilities.CopyMemory(memBuffers[nextBuffer].Pointer, bufferPointer.Pointer, bufferPointer.Size);
// Set the pointer to the data.
audioBuffersRing[nextBuffer].AudioDataPointer = memBuffers[nextBuffer].Pointer;
audioBuffersRing[nextBuffer].AudioBytes = bufferPointer.Size;
// If this is a first play, restart the clock and notify play method.
if (isFirstTime)
{
clock.Restart();
isFirstTime = false;
waitForPlayToOutput.Set();
}
// Update the current position used for sync
playPosition = new TimeSpan(playPositionStart.Ticks + clock.Elapsed.Ticks);
// Submit the audio buffer to xaudio2
sourceVoice.SubmitSourceBuffer(audioBuffersRing[nextBuffer], null);
// Go to next entry in the ring audio buffer
nextBuffer = ++nextBuffer%audioBuffersRing.Length;
var crossFadePosition = CrossFadePosition;
if (crossFadePosition.HasValue)
{
// Fade down volume?
}
}
// If the song is not looping (by default), then stop the audio player.
if (endOfSong && !IsRepeating && State == AudioPlayerState.Playing)
{
if (AutoCloseAtEndOfSong)
{
Stop();
Dispose();
State = AudioPlayerState.Closed;
}
else
Stop();
}
}
} finally
{
DisposePlayer();
}
}