protected void WriteSamples(short[] samples, int count) { if (count == 0) { return; } HasAudio = true; if (_secondaryBuffer.Status == (int)BufferStatus.BufferLost) { _secondaryBuffer.Restore(); } //If synchronise wait until there is enough free space if (_synchronizationStrategy != null && _synchronizationStrategy.SyncToAudio) { Synchronize(count); } int samplesNeeded = GetSamplesNeeded(); if (samplesNeeded < 1) { return; } if (count > samplesNeeded) { count = samplesNeeded; } _secondaryBuffer.Write(samples, 0, count, _nextWrite, LockFlags.None); IncrementWritePosition(count * sizeof(short)); }
private bool CheckBufferIsLost(bool _throw) { //true - потерян if ((AudioBuffer.Status & (int)BufferStatus.BufferLost) == 0) { return(false); } //С первого раза может не получиться, но //и растягивать навечно смысла тоже нет.. for (int i = 0; i <= 10; i++) { try { AudioBuffer.Restore(); } catch (Exception) { /*Буфер пока-что не может быть восстановлен*/ } if ((AudioBuffer.Status & (int)BufferStatus.BufferLost) == 0) { return(false); } if (IsError || IsAborted) { return(true); } if (i == 10) { if (_throw) { throw new Exception(Languages.Translate("AudioBuffer is lost and can't be restored!") + "\r\n" + Languages.Translate("Probably some other application uses it with higher privilege level.")); } else { return(true); } } else { Thread.Sleep(100); if (IsError || IsAborted) { return(true); } } } return(true); }
//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; //} }
private void StartPlaying() { _actualWriteOffsetBytes = -1; _filledBufferSizeBytes = 0; _lastWriteTime = 0; _lastWriteCursor = 0; int attempts = _retryCounter; while (!IsPlaying && attempts > 0) { attempts--; try { if (_deviceBuffer == null) { var format = new WaveFormat { SamplesPerSecond = _sound.SampleRate, BitsPerSample = (short)(_sound.BytesPerSample * 8), Channels = (short)_sound.ChannelCount, FormatTag = WaveFormatTag.Pcm, BlockAlignment = (short)_sound.BlockAlign, AverageBytesPerSecond = _sound.SampleRate * _sound.BlockAlign }; var desc = new SoundBufferDescription { Format = format, Flags = BufferFlags.GlobalFocus | BufferFlags.Software | BufferFlags.GetCurrentPosition2 | BufferFlags.ControlVolume, SizeInBytes = BufferSizeBytes }; _deviceBuffer = new SecondarySoundBuffer(_device, desc); } _deviceBuffer.Play(0, PlayFlags.Looping); } catch (DirectSoundException) { if (_deviceBuffer != null) { _deviceBuffer.Restore(); } if (attempts > 0) { System.Threading.Thread.Sleep(10); } } } if (IsPlaying) { _retryCounter = 5; } else if (_retryCounter > 1) { _retryCounter--; } }
public void Write(short[] sampleBuffer) { lock (this) { if (!Started) { return; } if (Secondary == null || InputSamplingRate == 0 || RealAudioSamplingRate == 0) { ErrorString = "Invalid sampling rate"; return; } try { /* resample shorts in sampleBuffer */ if (InputSamplingRate != RealAudioSamplingRate) { if (ResampleIn.Length != sampleBuffer.Length) { Array.Resize(ref ResampleIn, sampleBuffer.Length); } for (int pos = 0; pos < sampleBuffer.Length; pos++) { ResampleIn[pos] = sampleBuffer[pos] / (double)short.MaxValue; } SignalResampler.Oversampling = (decimal)RealAudioSamplingRate / InputSamplingRate; SignalResampler.Resample(ResampleIn, ref ResampledOut); if (ResampledShorts.Length != ResampledOut.Length) { Array.Resize(ref ResampledShorts, ResampledOut.Length); } for (int pos = 0; pos < ResampledShorts.Length; pos++) { ResampledShorts[pos] = (short)(ResampledOut[pos] * (double)short.MaxValue); } sampleBuffer = ResampledShorts; } int samplesToWrite = sampleBuffer.Length; int bytesToWrite = samplesToWrite * Secondary.Format.BlockAlignment; int currentPlayPosition = Secondary.CurrentPlayPosition; /* get the number of samples that we are able to write total */ int bytesUsed = CurrentWritePosition - Secondary.CurrentWritePosition; if (bytesUsed < 0) { bytesUsed += BufferSize; } /* keep one sample free */ int bytesFree = BufferSize - bytesUsed; int samplesFree = bytesFree / Secondary.Format.BlockAlignment; int maxSamples = Math.Min(samplesFree, samplesToWrite); if (maxSamples == 0) { CurrentWritePosition = 0; maxSamples = samplesToWrite; } if (Secondary.Status == BufferStatus.BufferLost) { Secondary.Restore(); } /* can be written at once? or must be written in two steps? */ if (CurrentWritePosition + maxSamples > BufferSize) { int samplesFirst = BufferSize - CurrentWritePosition; int samplesSecond = maxSamples - samplesFirst; Secondary.Write(sampleBuffer, 0, samplesFirst, CurrentWritePosition, LockFlags.None); /* write the second block at position 0 */ Secondary.Write(sampleBuffer, samplesFirst, samplesSecond, 0, LockFlags.None); } else { if (maxSamples > 0) { Secondary.Write(sampleBuffer, 0, maxSamples, CurrentWritePosition, LockFlags.None); } } /* whole data was written, increment position */ CurrentWritePosition += bytesToWrite; CurrentWritePosition %= BufferSize; BytesWritten += bytesToWrite; /* start playing when n packets were buffered */ if (!PlayingStarted && BytesWritten > PrebufferBytes) { PlayingStarted = true; Secondary.CurrentPlayPosition = 0; Secondary.Play(0, PlayFlags.Looping); } ErrorString = null; } catch (Exception e) { ErrorString = "Processing Exception"; Console.Out.WriteLine("Exception: " + e.ToString()); Stop(); return; } } }