/// <summary> /// Plays specified audio data bytes. If player is currently playing, data will be queued for playing. /// </summary> /// <param name="audioData">Audio data. Data boundary must n * BlockSize.</param> /// <param name="offset">Offset in the buffer.</param> /// <param name="count">Number of bytes to play form the specified offset.</param> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception> /// <exception cref="ArgumentNullException">Is raised when <b>audioData</b> is null.</exception> /// <exception cref="ArgumentException">Is raised when <b>audioData</b> is with invalid length.</exception> public void Play(byte[] audioData,int offset,int count) { if(m_IsDisposed){ throw new ObjectDisposedException("WaveOut"); } if(audioData == null){ throw new ArgumentNullException("audioData"); } if((count % m_BlockSize) != 0){ throw new ArgumentException("Audio data is not n * BlockSize."); } //--- Queue specified audio block for play. -------------------------------------------------------- byte[] data = new byte[count]; Array.Copy(audioData,offset,data,0,count); GCHandle dataHandle = GCHandle.Alloc(data,GCHandleType.Pinned); // m_BytesBuffered += data.Length; WAVEHDR wavHeader = new WAVEHDR(); wavHeader.lpData = dataHandle.AddrOfPinnedObject(); wavHeader.dwBufferLength = (uint)data.Length; wavHeader.dwBytesRecorded = 0; wavHeader.dwUser = IntPtr.Zero; wavHeader.dwFlags = 0; wavHeader.dwLoops = 0; wavHeader.lpNext = IntPtr.Zero; wavHeader.reserved = 0; GCHandle headerHandle = GCHandle.Alloc(wavHeader,GCHandleType.Pinned); int result = 0; result = WavMethods.waveOutPrepareHeader(m_pWavDevHandle,headerHandle.AddrOfPinnedObject(),Marshal.SizeOf(wavHeader)); if(result == MMSYSERR.NOERROR){ PlayItem item = new PlayItem(ref headerHandle,ref dataHandle,data.Length); m_pPlayItems.Add(item); // We ran out of minimum buffer, we must pause playing while min buffer filled. if(m_BytesBuffered < 1000){ if(!m_IsPaused){ WavMethods.waveOutPause(m_pWavDevHandle); m_IsPaused = true; } //File.AppendAllText("aaaa.txt","Begin buffer\r\n"); } // Buffering completed,we may resume playing. else if(m_IsPaused && m_BytesBuffered > m_MinBuffer){ WavMethods.waveOutRestart(m_pWavDevHandle); m_IsPaused = false; //File.AppendAllText("aaaa.txt","end buffer: " + m_BytesBuffered + "\r\n"); } /* // TODO: If we ran out of minimum buffer, we must pause playing while min buffer filled. if(m_BytesBuffered < m_MinBuffer){ if(!m_IsPaused){ WavMethods.waveOutPause(m_pWavDevHandle); m_IsPaused = true; } } else if(m_IsPaused){ WavMethods.waveOutRestart(m_pWavDevHandle); }*/ m_BytesBuffered += data.Length; result = WavMethods.waveOutWrite(m_pWavDevHandle,headerHandle.AddrOfPinnedObject(),Marshal.SizeOf(wavHeader)); } else{ dataHandle.Free(); headerHandle.Free(); } //-------------------------------------------------------------------------------------------------- }
/// <summary> /// Fills recording buffers. /// </summary> private void EnsureBuffers() { // We keep 3 x buffer. lock(m_pBuffers){ while(m_pBuffers.Count < 3){ byte[] data = new byte[m_BufferSize]; GCHandle dataHandle = GCHandle.Alloc(data,GCHandleType.Pinned); WAVEHDR wavHeader = new WAVEHDR(); wavHeader.lpData = dataHandle.AddrOfPinnedObject(); wavHeader.dwBufferLength = (uint)data.Length; wavHeader.dwBytesRecorded = 0; wavHeader.dwUser = IntPtr.Zero; wavHeader.dwFlags = 0; wavHeader.dwLoops = 0; wavHeader.lpNext = IntPtr.Zero; wavHeader.reserved = 0; GCHandle headerHandle = GCHandle.Alloc(wavHeader,GCHandleType.Pinned); int result = 0; result = WavMethods.waveInPrepareHeader(m_pWavDevHandle,headerHandle.AddrOfPinnedObject(),Marshal.SizeOf(wavHeader)); if(result == MMSYSERR.NOERROR){ m_pBuffers.Add(new BufferItem(ref headerHandle,ref dataHandle,m_BufferSize)); result = WavMethods.waveInAddBuffer(m_pWavDevHandle,headerHandle.AddrOfPinnedObject(),Marshal.SizeOf(wavHeader)); if(result != MMSYSERR.NOERROR){ throw new Exception("Error adding wave in buffer, error: " + result + "."); } } } } }