private static void osd_update_audio_stream(byte[] buffer, int samples_this_frame) { int play_position, write_position; int stream_in; byte[] buffer1, buffer2; int length1, length2; buf2.GetCurrentPosition(out play_position, out write_position); if (write_position < play_position) { write_position += 0x9400; } stream_in = stream_buffer_in; if (stream_in < write_position) { stream_in += 0x9400; } while (stream_in < write_position) { //buffer_underflows++; stream_in += 0xf00; } if (stream_in + 0xf00 > play_position + 0x9400) { //buffer_overflows++; return; } stream_buffer_in = stream_in % 0x9400; if (stream_buffer_in + 0xf00 < 0x9400) { length1 = 0xf00; length2 = 0; buffer1 = new byte[length1]; Array.Copy(buffer, buffer1, length1); buf2.Write(stream_buffer_in, buffer1, LockFlag.None); stream_buffer_in = stream_buffer_in + 0xf00; } else if (stream_buffer_in + 0xf00 == 0x9400) { length1 = 0xf00; length2 = 0; buffer1 = new byte[length1]; Array.Copy(buffer, buffer1, length1); buf2.Write(stream_buffer_in, buffer1, LockFlag.None); stream_buffer_in = 0; } else if (stream_buffer_in + 0xf00 > 0x9400) { length1 = 0x9400 - stream_buffer_in; length2 = 0xf00 - length1; buffer1 = new byte[length1]; buffer2 = new byte[length2]; Array.Copy(buffer, buffer1, length1); Array.Copy(buffer, length1, buffer2, 0, length2); buf2.Write(stream_buffer_in, buffer1, LockFlag.None); buf2.Write(0, buffer2, LockFlag.None); stream_buffer_in = length2; } }
public void Pause() { if (buffer != null) { try { if (buffer.Status.Playing) { buffer.Stop(); } } catch (AccessViolationException) { } int trash; buffer.GetCurrentPosition(out m_lastPlayingPosition, out trash); } }
void Play() { int playPos; int writePos; int lockSize; try { m_Buffer.GetCurrentPosition(out playPos, out writePos); lockSize = writePos - nextWriteOffset; if (lockSize < 0) { lockSize += m_BufferBytes; } // Block align lock size so that we are always write on a boundary lockSize -= (lockSize % notifySize); if (0 == lockSize) { return; } if (lockSize == m_BufferBytes) { } byte[] writeBytes = new byte[lockSize]; if (circularBuffer.Read(writeBytes) > 0) { m_Buffer.Write(nextWriteOffset, writeBytes, LockFlag.None); // Move the capture offset along nextWriteOffset += lockSize; nextWriteOffset %= m_BufferBytes; // Circular buffer } } catch (Exception) { } finally { } }
/// <summary> /// The stream control thread raises events every half the stream. /// When the BufferNotificationEventArgs contains a SoundFinished property set to true, the /// current buffer segment is padded with silence. At the next notification, the next /// buffer segment is filled with silence, and no event is raised. /// At the next notification, which will come when the padded segment /// (not the completely silent segment) is finished, the SecondaryBuffer is stopped and /// the thread terminated. /// </summary> private void StreamControlThread() { int nextPlaceForBytes = 0; int wholeBufferSize = SB.Caps.BufferBytes; int byteWindowSize = wholeBufferSize / 2; NextNotificationTask task = NextNotificationTask.FillSectionWithNewSound; //BufferNotificationEventArgs ssea = new BufferNotificationEventArgs(SB.Caps.BufferBytes); BufferNotificationEventArgs firstNotificationEventArgs = new BufferNotificationEventArgs(wholeBufferSize); GetBytesByRaisingEvent(0, wholeBufferSize, firstNotificationEventArgs); task = HandleNewBytesInControlThread(nextPlaceForBytes, wholeBufferSize, firstNotificationEventArgs); bool terminate = false; while (!terminate) { NotificationEvent.Reset(); NotificationEvent.WaitOne(); if (SB.Disposed || (!Playing)) { break; } /// Very strange behavior from DirectSound!! /// SB.PlayPosition returns a value slightly less than the actual position. Either that or the event is raised /// So you can use that to determine which section to fill. Fill the half that you're currently "playing" /// according to the PlayPosition. /// If anyone knows how to do this properly, please e-mail me, [email protected]. int playPosition = SB.PlayPosition; int distToBegin = Math.Abs(playPosition - 0); int distToEnd = Math.Abs(playPosition - wholeBufferSize); int distToMid = Math.Abs(playPosition - byteWindowSize); if (distToMid < distToEnd && distToMid < distToBegin) { nextPlaceForBytes = 0; } else { nextPlaceForBytes = byteWindowSize; } //Console.WriteLine(DateTime.Now + ": Received request for bytes at " + nextPlaceForBytes + " and I'm now at " + SB.PlayPosition); switch (task) { case NextNotificationTask.FillSectionWithNewSound: BufferNotificationEventArgs nextNotificationEventArgs = new BufferNotificationEventArgs(byteWindowSize); GetBytesByRaisingEvent(nextPlaceForBytes, byteWindowSize, nextNotificationEventArgs); task = HandleNewBytesInControlThread(nextPlaceForBytes, byteWindowSize, nextNotificationEventArgs); break; case NextNotificationTask.FillSectionWithSilence: task = NextNotificationTask.StopSecondaryBufferAndThread; //Console.WriteLine("Filling section with silence at " + nextPlaceForBytes); int currentPosition = 0; int writePos = 0; SB.GetCurrentPosition(out currentPosition, out writePos); //Console.WriteLine("Current pos " + currentPosition + " and writing " + byteWindowSize + " at " + nextPlaceForBytes); SB.Write(nextPlaceForBytes, new byte[byteWindowSize], LockFlag.None); break; default: // NextNotificationTask.StopSecondaryBufferAndThread SB.Stop(); //Console.WriteLine("stream control thread dies."); return; } //nextPlaceForBytes += byteWindowSize; if (nextPlaceForBytes >= SB.Caps.BufferBytes) nextPlaceForBytes = 0; } //Console.WriteLine("stream control thread dies."); }
public void Write(AudioBuffer src) { //wavoutput.Write(src); pcmStream.SetLength(0); pcmStream.Write(src.Bytes, 0, src.ByteLength); pcmStream.Position = 0; //pcmStream.Position = 0; //while (true) //{ // if (SecBufInitialLoad) // { // int count = Math.Min(src.ByteLength, SecBufByteSize - SecBufNextWritePosition); // if (count > 0) // { // secondaryBuffer.Write(SecBufNextWritePosition, pcmStream, count, LockFlag.None); // SecBufNextWritePosition += count; // pcmStream.Position += count; // } // if (SecBufByteSize == SecBufNextWritePosition) // { // // Finished filling the buffer // SecBufInitialLoad = false; // SecBufNextWritePosition = 0; // // So start the playback in its own thread // secondaryBuffer.Play(0, BufferPlayFlags.Looping); // // Yield rest of timeslice so playback can // // start right away. // Thread.Sleep(0); // } // else // { // continue; // Get more PCM data // } // } // Exhaust the current PCM data by writing the data into secondaryBuffer while (pcmStream.Position < pcmStream.Length) { int PlayPosition, WritePosition; secondaryBuffer.GetCurrentPosition(out PlayPosition, out WritePosition); int WriteCount = (int)Math.Min( (SecBufByteSize + PlayPosition - WritePosition) % SecBufByteSize, pcmStream.Length - pcmStream.Position); if (WriteCount > 0) { secondaryBuffer.Write( WritePosition, pcmStream, WriteCount, LockFlag.None); pcmStream.Position += WriteCount; if (!playing) { secondaryBuffer.Play(0, 0); playing = true; } } else { WaitHandle.WaitAny(SecBufWaitHandles, new TimeSpan(0, 0, 5), true); } } }
/// <summary> /// 将新收到的音频数据存入辅助播放缓冲区,准备播放 /// </summary> /// <param name="secBuf">辅助播放缓冲区</param> void m_objVP_ReadyForNewData(SecondaryBuffer secBuf) { try { int curPlayPos, curWritePos; secBuf.GetCurrentPosition(out curPlayPos, out curWritePos); // Write( "curWritePos[" + curWritePos.ToString() + "]" // + "curPlay[" + curPlayPos.ToString() + "]"); // 写到下一个写入通知之前 int lockSize;// = m_nNextWritePos - curWritePos; #region 测试代码 //curWritePos = (curWritePos / m_objVP.nNotifySize) * m_objVP.nNotifySize; lockSize = m_objVP.nNotifySize; #endregion if (lockSize < 0) lockSize += m_objVP.nBufSize; if (0 != lockSize) { byte[] data = new byte[lockSize]; if (m_objBuf.Read(data) > 0) { secBuf.Write(curWritePos, data, LockFlag.FromWriteCursor); m_nNextWritePos = (m_nNextWritePos + m_objVP.nNotifySize) % m_objVP.nBufSize; // Write( "curWritePos[" + curWritePos.ToString() + "]" // + "dataLength[" + data.Length.ToString() + "]"); } // end of if } // end of if } catch { } }