//private long m_CircularBufferFlushTolerance; //private int m_CircularBufferPreviousBytesAvailableForWriting; private bool circularBufferRefreshThreadMethod() { //m_CircularBufferRefreshThreadIsAlive = true; //float previousFastPlayFactor = m_FastPlayFactor; //long predictedByteIncrement = -1; //int circularBufferTotalBytesPlayed = -1; //int previousCircularBufferPlayPosition = -1; Stopwatch transferBytesStopWatch = new Stopwatch(); transferBytesStopWatch.Stop(); int totalWriteSkips = 0; uint adjustedFastPlaySampleRate = (uint)Math.Round(m_CurrentAudioPCMFormat.SampleRate * m_FastPlayFactor); long pcmDataTotalPlayableFromStream = m_PlaybackEndPositionInCurrentAudioStream - m_PlaybackStartPositionInCurrentAudioStream; long pcmDataTotalPlayableFromStream_DurationMS = ( NotNormalPlayFactor() ? AudioLibPCMFormat.ConvertBytesToTime( pcmDataTotalPlayableFromStream, adjustedFastPlaySampleRate, m_CurrentAudioPCMFormat.BlockAlign #if DEBUG , true #endif ) : m_CurrentAudioPCMFormat.ConvertBytesToTime(pcmDataTotalPlayableFromStream) ) / AudioLibPCMFormat.TIME_UNIT; int slowLoop = 0; int sleepTime = REFRESH_INTERVAL_MS; //bool endOfAudioStream = false; while (true) { #if USE_SHARPDX DebugFix.Assert( m_CircularBuffer.Status == (int)BufferStatus.BufferLost || m_CircularBuffer.Status == (int)BufferStatus.Hardware || m_CircularBuffer.Status == (int)BufferStatus.Looping || m_CircularBuffer.Status == (int)BufferStatus.None || m_CircularBuffer.Status == (int)BufferStatus.Playing || m_CircularBuffer.Status == (int)BufferStatus.Software || m_CircularBuffer.Status == (int)BufferStatus.Terminated || m_CircularBuffer.Status == 5 //?! ); if (m_CircularBuffer.Status == (int)BufferStatus.BufferLost) { m_CircularBuffer.Restore(); } #else if (m_CircularBuffer.Status.BufferLost) { m_CircularBuffer.Restore(); } #endif #if USE_SHARPDX if (m_CircularBuffer.Status == (int)BufferStatus.Terminated || (m_CircularBuffer.Status != 5 && //?! m_CircularBuffer.Status != (int)BufferStatus.Playing && m_CircularBuffer.Status != (int)BufferStatus.Looping) ) { return(false); } #else if (m_CircularBuffer.Status.Terminated || (!m_CircularBuffer.Status.Playing && !m_CircularBuffer.Status.Looping) ) { return(false); } #endif Thread.Sleep(sleepTime); sleepTime = REFRESH_INTERVAL_MS; // reset after each loop // if (predictedByteIncrement < 0 // || true //m_FastPlayFactor != previousFastPlayFactor // ) // { // //previousFastPlayFactor = m_FastPlayFactor; // int fastPlaySamplesPerSecond = (int)Math.Round(m_CurrentAudioPCMFormat.SampleRate * m_FastPlayFactor); //#if DEBUG // DebugFix.Assert(m_CurrentAudioPCMFormat.SampleRate == m_CircularBuffer.Format.SamplesPerSecond); // if ( //#if USE_SOUNDTOUCH //!UseSoundTouch && //#endif //USE_SOUNDTOUCH //#if USE_SHARPDX // m_CircularBuffer.Capabilities.ControlFrequency //#else // m_CircularBuffer.Caps.ControlFrequency //#endif //) // { // DebugFix.Assert(m_CircularBuffer.Frequency == fastPlaySamplesPerSecond); // } //#endif //DEBUG // int byteRate = fastPlaySamplesPerSecond * m_CurrentAudioPCMFormat.BlockAlign; // (m_CurrentAudioPCMFormat.BitDepth / 8) * m_CurrentAudioPCMFormat.NumberOfChannels; // predictedByteIncrement = (long)(byteRate * (REFRESH_INTERVAL_MS + 15) / 1000.0); // predictedByteIncrement -= predictedByteIncrement % m_CurrentAudioPCMFormat.BlockAlign; // } #if USE_SHARPDX int circularBufferPlayPosition; int circularBufferWritePosition; m_CircularBuffer.GetCurrentPosition(out circularBufferPlayPosition, out circularBufferWritePosition); #else int circularBufferPlayPosition = m_CircularBuffer.PlayPosition; #endif int circularBufferLength = m_CircularBuffer. #if USE_SHARPDX Capabilities #else Caps #endif .BufferBytes ; //if (circularBufferTotalBytesPlayed < 0) //{ // circularBufferTotalBytesPlayed = circularBufferPlayPosition; //} //else //{ // if (circularBufferPlayPosition >= previousCircularBufferPlayPosition) // { // circularBufferTotalBytesPlayed += circularBufferPlayPosition - previousCircularBufferPlayPosition; // } // else // { // circularBufferTotalBytesPlayed += (circularBufferLength - previousCircularBufferPlayPosition) + circularBufferPlayPosition; // } //} //previousCircularBufferPlayPosition = circularBufferPlayPosition; // int totalBytesPlayed_AdjustedPlaybackRate = circularBufferTotalBytesPlayed; //#if USE_SOUNDTOUCH // if (UseSoundTouch && NotNormalPlayFactor()) // { // //m_CurrentAudioPCMFormat // totalBytesPlayed_AdjustedPlaybackRate = (int)Math.Round(totalBytesPlayed_AdjustedPlaybackRate * m_FastPlayFactor); // totalBytesPlayed_AdjustedPlaybackRate -= totalBytesPlayed_AdjustedPlaybackRate % m_CurrentAudioPCMFormat.BlockAlign; // } //#endif //USE_SOUNDTOUCH int circularBufferBytesAvailableForWriting = (circularBufferPlayPosition == m_CircularBufferWritePosition ? 0 : (circularBufferPlayPosition < m_CircularBufferWritePosition ? circularBufferPlayPosition + (circularBufferLength - m_CircularBufferWritePosition) : circularBufferPlayPosition - m_CircularBufferWritePosition)); //int circularBufferBytesAvailableForPlaying = circularBufferLength - circularBufferBytesAvailableForWriting; //realTimePlaybackPosition -= realTimePlaybackPosition % m_CurrentAudioPCMFormat.BlockAlign; //Console.WriteLine(String.Format("bytesAvailableForWriting: [{0} / {1}]", bytesAvailableForWriting, m_CircularBuffer.Caps.BufferBytes)); //Console.WriteLine("dataAvailableFromStream: " + dataAvailableFromStream); // int circularBufferBytesAvailableForPlaying_AdjustedPlaybackRate = circularBufferBytesAvailableForPlaying; //#if USE_SOUNDTOUCH // if (UseSoundTouch && NotNormalPlayFactor()) // { // circularBufferBytesAvailableForPlaying_AdjustedPlaybackRate = (int)Math.Round(circularBufferBytesAvailableForPlaying_AdjustedPlaybackRate * m_FastPlayFactor); // circularBufferBytesAvailableForPlaying_AdjustedPlaybackRate -= circularBufferBytesAvailableForPlaying_AdjustedPlaybackRate % m_CurrentAudioPCMFormat.BlockAlign; // } //#endif //USE_SOUNDTOUCH long totalPlayedMS = m_PlaybackStopWatch.ElapsedMilliseconds; long totalPlayedBytes = ( NotNormalPlayFactor() ? AudioLibPCMFormat.ConvertTimeToBytes( totalPlayedMS * AudioLibPCMFormat.TIME_UNIT, (uint)adjustedFastPlaySampleRate, (ushort)m_CurrentAudioPCMFormat.BlockAlign #if DEBUG , true #endif ) : m_CurrentAudioPCMFormat.ConvertTimeToBytes(totalPlayedMS * AudioLibPCMFormat.TIME_UNIT) ); m_CurrentBytePosition = m_PlaybackStartPositionInCurrentAudioStream + totalPlayedBytes; //safeguard if (m_CurrentBytePosition < m_PlaybackStartPositionInCurrentAudioStream) { m_CurrentBytePosition = m_PlaybackStartPositionInCurrentAudioStream; } else if (m_CurrentBytePosition > m_PlaybackEndPositionInCurrentAudioStream) { m_CurrentBytePosition = m_PlaybackEndPositionInCurrentAudioStream; } //#if DEBUG // DebugFix.Assert(m_CurrentBytePosition >= m_PlaybackStartPositionInCurrentAudioStream); // DebugFix.Assert(m_CurrentBytePosition <= m_PlaybackEndPositionInCurrentAudioStream); //#endif // DEBUG //long remainingBytesToPlay = pcmDataTotalPlayableFromStream - totalBytesPlayed_AdjustedPlaybackRate; //long realTimePlaybackPosition = Math.Max(m_PlaybackStartPositionInCurrentAudioStream, // m_CurrentAudioStream.Position - Math.Min( // circularBufferBytesAvailableForPlaying_AdjustedPlaybackRate, remainingBytesToPlay)); //realTimePlaybackPosition = Math.Min(realTimePlaybackPosition, // m_PlaybackStartPositionInCurrentAudioStream + totalBytesPlayed_AdjustedPlaybackRate); //if (m_CurrentBytePosition == m_PlaybackStartPositionInCurrentAudioStream) //{ // //Console.WriteLine(string.Format("m_CurrentBytePosition ASSIGNED: realTimePlaybackPosition [{0}]", realTimePlaybackPosition)); // m_CurrentBytePosition += totalBytesPlayed_AdjustedPlaybackRate; //} ////else if (realTimePlaybackPosition < m_CurrentBytePosition) ////{ //// Console.WriteLine(string.Format("realTimePlaybackPosition [{0}] < m_CurrentBytePosition [{1}]", realTimePlaybackPosition, m_CurrentBytePosition)); //// m_CurrentBytePosition = Math.Min(m_PlaybackEndPositionInCurrentAudioStream, m_CurrentBytePosition + predictedByteIncrement); ////} ////else if (realTimePlaybackPosition > m_CurrentBytePosition + predictedByteIncrement) ////{ //// Console.WriteLine(string.Format("realTimePlaybackPosition [{0}] > m_CurrentBytePosition [{1}] + m_PredictedByteIncrement: [{2}] (diff: [{3}])", //// realTimePlaybackPosition, m_CurrentBytePosition, predictedByteIncrement, realTimePlaybackPosition - m_CurrentBytePosition)); //// m_CurrentBytePosition = Math.Min(m_PlaybackEndPositionInCurrentAudioStream, m_CurrentBytePosition + predictedByteIncrement); ////} //else //{ // //Console.WriteLine(string.Format("m_CurrentBytePosition OK: realTimePlaybackPosition [{0}]", realTimePlaybackPosition)); // m_CurrentBytePosition = m_PlaybackStartPositionInCurrentAudioStream + totalBytesPlayed_AdjustedPlaybackRate; //} PcmDataBufferAvailableHandler del = PcmDataBufferAvailable; if (del != null) { int min = Math.Min(m_PcmDataBufferLength, #if FETCH_PCM_FROM_CIRCULAR_BUFFER circularBufferBytesAvailableForPlaying #else (int)(m_PlaybackEndPositionInCurrentAudioStream - m_CurrentBytePosition) #endif // FETCH_PCM_FROM_CIRCULAR_BUFFER ); #if DEBUG DebugFix.Assert(min <= m_PcmDataBufferLength); DebugFix.Assert(min <= m_PcmDataBuffer.Length); #endif //DEBUG if (min >= m_CurrentAudioPCMFormat.BlockAlign) { #if FETCH_PCM_FROM_CIRCULAR_BUFFER #if USE_SHARPDX if (SharpDX_IntermediaryTransferBuffer != null) { Array.Copy(SharpDX_IntermediaryTransferBuffer, m_PcmDataBuffer, Math.Min(m_PcmDataBuffer.Length, SharpDX_IntermediaryTransferBuffer.Length)); } #else byte[] array = (byte[])m_CircularBuffer.Read( circularBufferPlayPosition, typeof(byte), LockFlag.None, min); //Array.Copy(array, m_PcmDataBuffer, min); Buffer.BlockCopy(array, 0, m_PcmDataBuffer, 0, min); #endif #else // !FETCH_PCM_FROM_CIRCULAR_BUFFER long pos = m_CurrentAudioStream.Position; m_CurrentAudioStream.Position = m_CurrentBytePosition; m_CurrentAudioStream.Read(m_PcmDataBuffer, 0, min); m_CurrentAudioStream.Position = pos; #endif m_PcmDataBufferAvailableEventArgs.PcmDataBuffer = m_PcmDataBuffer; m_PcmDataBufferAvailableEventArgs.PcmDataBufferLength = min; del(this, m_PcmDataBufferAvailableEventArgs); } } //var del_ = PcmDataBufferAvailable; //if (del_ != null //&& m_PcmDataBuffer.Length <= circularBufferBytesAvailableForPlaying) //{ //#if USE_SHARPDX //if (SharpDX_IntermediaryTransferBuffer != null) //{ //Array.Copy(SharpDX_IntermediaryTransferBuffer, m_PcmDataBuffer, Math.Min(m_PcmDataBuffer.Length, SharpDX_IntermediaryTransferBuffer.Length)); //m_PcmDataBufferAvailableEventArgs.PcmDataBuffer = m_PcmDataBuffer; //PcmDataBufferAvailable(this, m_PcmDataBufferAvailableEventArgs); //} //#else //Array array = m_CircularBuffer.Read(circularBufferPlayPosition, typeof(byte), LockFlag.None, m_PcmDataBuffer.Length); //Array.Copy(array, m_PcmDataBuffer, m_PcmDataBuffer.Length); //m_PcmDataBufferAvailableEventArgs.PcmDataBuffer = m_PcmDataBuffer; //del_(this, m_PcmDataBufferAvailableEventArgs); //#endif //} long pcmDataRemainingPlayableFromStream = m_PlaybackEndPositionInCurrentAudioStream - m_CurrentAudioStream.Position; //long pcmDataAlreadyReadFromStream = pcmDataTotalPlayableFromStream - pcmDataAvailableFromStream; if (circularBufferBytesAvailableForWriting <= 0) { if (pcmDataRemainingPlayableFromStream > 0) { //Console.WriteLine("circularBufferBytesAvailableForWriting <= 0, pcmDataAvailableFromStream > 0 ... continue..."); continue; } else { Console.WriteLine("circularBufferBytesAvailableForWriting <= 0, pcmDataAvailableFromStream <= 0 ... BREAK..."); break; } } //m_CircularBufferPreviousBytesAvailableForWriting = circularBufferBytesAvailableForWriting; // We have fed all of the available bytes from the audio stream to the circular secondary buffer. // Now we have to wait until the playback ends. if (pcmDataRemainingPlayableFromStream <= 0) { if ((m_PlaybackStopWatch.ElapsedMilliseconds + REFRESH_INTERVAL_MS) >= pcmDataTotalPlayableFromStream_DurationMS) { m_CircularBuffer.Stop(); return(true); } else { int newInterval = (int)Math.Round(REFRESH_INTERVAL_MS / 2.0); sleepTime = newInterval; continue; } //if (remainingBytesToPlay > predictedByteIncrement) //{ // Console.WriteLine(string.Format("remainingBytesToPlay [{0}] [{1}] [{2}] [{3}]", // pcmDataTotalPlayableFromStream, totalBytesPlayed_AdjustedPlaybackRate, remainingBytesToPlay, predictedByteIncrement)); // continue; //} //else //{ // m_CircularBuffer.Stop(); // //Console.WriteLine("Time to break, all bytes gone."); // //break; // return true; //} //if (m_CircularBufferFlushTolerance < 0) //{ // m_CircularBufferFlushTolerance = m_CurrentAudioPCMFormat.ConvertTimeToBytes(REFRESH_INTERVAL_MS*1.5); //} //Console.WriteLine(string.Format("pcmDataTotalPlayableFromStream [{0}]", pcmDataTotalPlayableFromStream)); //Console.WriteLine(String.Format("pcmDataAvailableFromStream <= 0 // circularBufferBytesAvailableForWriting [{0}], m_CircularBufferFlushTolerance [{1}], m_CircularBuffer.Caps.BufferBytes [{2}], m_CircularBufferPreviousBytesAvailableForWriting [{3}]", // circularBufferBytesAvailableForWriting, m_CircularBufferFlushTolerance, m_CircularBuffer.Caps.BufferBytes, m_CircularBufferPreviousBytesAvailableForWriting)); //if ((circularBufferBytesAvailableForWriting + m_CircularBufferFlushTolerance) >= m_CircularBuffer.Caps.BufferBytes // || m_CircularBufferPreviousBytesAvailableForWriting > circularBufferBytesAvailableForWriting) //{ // m_CircularBuffer.Stop(); // the earlier the better ? // Console.WriteLine("Forcing closing-up."); // circularBufferBytesAvailableForWriting = 0; // will enter the IF test below //} } else { // 2 thirds minimum of the circular buffer must be available, //otherwise skip until next sleep loop double ratio = 2 / 3.0; #if USE_SOUNDTOUCH if (UseSoundTouch && NotNormalPlayFactor()) { ratio /= m_FastPlayFactor; } #endif // USE_SOUNDTOUCH bool skip = circularBufferBytesAvailableForWriting < (int)Math.Round(circularBufferLength * ratio); if (false && skip) { totalWriteSkips++; } else { // int circularBufferBytesAvailableForWriting_AdjustedPlaybackRate = // circularBufferBytesAvailableForWriting; //#if USE_SOUNDTOUCH // if (UseSoundTouch && NotNormalPlayFactor()) // { // int bytesPerSample = (int)Math.Round(m_CurrentAudioPCMFormat.BitDepth / 8.0); // int bytesPerFrame = bytesPerSample * m_CurrentAudioPCMFormat.NumberOfChannels; // DebugFix.Assert(m_CurrentAudioPCMFormat.BlockAlign == bytesPerFrame); // circularBufferBytesAvailableForWriting_AdjustedPlaybackRate = // (int) // Math.Round(circularBufferBytesAvailableForWriting_AdjustedPlaybackRate // * m_FastPlayFactor // * m_CurrentAudioPCMFormat.NumberOfChannels); // circularBufferBytesAvailableForWriting_AdjustedPlaybackRate -= // circularBufferBytesAvailableForWriting_AdjustedPlaybackRate % // m_CurrentAudioPCMFormat.BlockAlign; // } //#endif //USE_SOUNDTOUCH //Console.WriteLine("totalWriteSkips: " + totalWriteSkips + " ms: " + totalWriteSkips*REFRESH_INTERVAL_MS); totalWriteSkips = 0; #if NET4 transferBytesStopWatch.Restart(); #else transferBytesStopWatch.Stop(); transferBytesStopWatch.Reset(); transferBytesStopWatch.Start(); #endif //NET4 int bytesWrittenToCirularBuffer = transferBytesFromWavStreamToCircularBuffer(circularBufferBytesAvailableForWriting); long timeMS = transferBytesStopWatch.ElapsedMilliseconds; transferBytesStopWatch.Stop(); //Console.WriteLine("transferBytesStopWatch: " + timeMS); sleepTime = Math.Max(10, REFRESH_INTERVAL_MS - (int)timeMS); #if USE_SOUNDTOUCH if (UseSoundTouch && NotNormalPlayFactor()) { if (timeMS >= REFRESH_INTERVAL_MS) { slowLoop++; } if (slowLoop > 2) { slowLoop = 0; Console.WriteLine("SOUNDTOUCH Enable SettingId.UseQuickseek"); m_SoundTouch.SetSetting(SettingId.UseQuickseek, 1); } } #endif //USE_SOUNDTOUCH //#if USE_SOUNDTOUCH // if (UseSoundTouch && NotNormalPlayFactor()) // { // int newInterval = (int)Math.Round(REFRESH_INTERVAL_MS / m_FastPlayFactor); // //sleepTime = newInterval; // } //#endif // USE_SOUNDTOUCH } } } // WHILE LOOP return(true); //CurrentState = State.Stopped; //AudioPlaybackFinishHandler delFinished = AudioPlaybackFinished; //if (delFinished != null && !mPreviewTimer.Enabled) // delFinished(this, new AudioPlaybackFinishEventArgs()); //if (!m_AllowBackToBackPlayback) //{ // AudioPlaybackFinishHandler delFinished = AudioPlaybackFinished; // if (delFinished != null && mEventsEnabled) // delFinished(this, new AudioPlaybackFinishEventArgs()); //} //else //{ // m_FinishedPlayingCurrentStream = true; //} }