Exemplo n.º 1
0
        /// <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 + ".");
                        }
                    }
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Cleans up any resources being used.
        /// </summary>
        public void Dispose()
        {
            if (m_IsDisposed)
            {
                return;
            }
            m_IsDisposed = true;

            // Release events.
            this.BufferFull = null;

            try{
                // If recording, we need to reset wav device first.
                WavMethods.waveInReset(m_pWavDevHandle);

                // If there are unprepared wav headers, we need to unprepare these.
                foreach (BufferItem item in m_pBuffers)
                {
                    WavMethods.waveInUnprepareHeader(m_pWavDevHandle, item.HeaderHandle.AddrOfPinnedObject(), Marshal.SizeOf(item.Header));
                    item.Dispose();
                }

                // Close input device.
                WavMethods.waveInClose(m_pWavDevHandle);

                m_pInDevice     = null;
                m_pWavDevHandle = IntPtr.Zero;
            }
            catch {
            }
        }
Exemplo n.º 3
0
 /// <summary>
 /// Cleans up any resources being used.
 /// </summary>
 public void Dispose()
 {
     if (m_IsDisposed)
     {
         return;
     }
     m_IsDisposed = true;
     lock (m_pPlayItems) {
         try {
             // If playing, we need to reset wav device first.
             WavMethods.waveOutReset(m_pWavDevHandle);
             // If there are unprepared wav headers, we need to unprepare these.
             foreach (PlayItem item in m_pPlayItems)
             {
                 WavMethods.waveOutUnprepareHeader(m_pWavDevHandle, item.HeaderHandle.AddrOfPinnedObject(), Marshal.SizeOf(item.Header));
                 item.Dispose();
             }
             // Close output device.
             WavMethods.waveOutClose(m_pWavDevHandle);
             m_pOutDevice    = null;
             m_pWavDevHandle = IntPtr.Zero;
             m_pPlayItems    = null;
             m_pWaveOutProc  = null;
         } catch {
         }
     }
 }
Exemplo n.º 4
0
        /// <summary>
        /// Processes first first filled buffer in queue and disposes it if done.
        /// </summary>
        /// <param name="state">User data.</param>
        private void ProcessFirstBuffer(object state)
        {
            try {
                lock (m_pBuffers) {
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    BufferItem item = m_pBuffers[0];

                    // Raise BufferFull event.
                    OnBufferFull(item.Data);
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    // Clean up.
                    WavMethods.waveInUnprepareHeader(m_pWavDevHandle, item.HeaderHandle.AddrOfPinnedObject(), Marshal.SizeOf(item.Header));
                    m_pBuffers.Remove(item);
                    item.Dispose();
                }

                EnsureBuffers();
            } catch {
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Sets audio output volume.
        /// </summary>
        /// <param name="left">Left channel volume level.</param>
        /// <param name="right">Right channel volume level.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        public void SetVolume(ushort left, ushort right)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("WaveOut");
            }

            WavMethods.waveOutSetVolume(m_pWavDevHandle, (right << 16 | left & 0xFFFF));
        }
Exemplo n.º 6
0
 public void Continue()
 {
     if (!m_IsPaused)
     {
         return;
     }
     lock (m_pPlayItems) {
         m_IsPaused = false;
         WavMethods.waveOutRestart(m_pWavDevHandle);
     }
 }
Exemplo n.º 7
0
 public void Pause()
 {
     if (m_IsPaused)
     {
         return;
     }
     lock (m_pPlayItems) {
         m_IsPaused = true;
         WavMethods.waveOutPause(m_pWavDevHandle);
     }
 }
Exemplo n.º 8
0
        protected virtual void Dispose(bool disposing)
        {
            if (!m_IsDisposed)
            {
                // Release events.
                this.BufferFull = null;

                try
                {
                    // If recording, we need to reset wav device first.
                    WavMethods.waveInReset(m_pWavDevHandle);

                    // If there are unprepared wav headers, we need to unprepare these.
                    lock (m_pBuffers)
                    {
                        foreach (BufferItem item in m_pBuffers)
                        {
                            try
                            {
                                WavMethods.waveInUnprepareHeader(m_pWavDevHandle, item.HeaderHandle.AddrOfPinnedObject(), Marshal.SizeOf(item.Header));
                            }
                            catch
                            {
                                Debug.WriteLine("WaveIn.Dispose() - WavMethods.waveInUnprepareHeader()");
                            }
                            item.Dispose();
                        }
                    }

                    // Close input device.
                    Debug.WriteLine("WaveIn.Dispose() - waveInClose");
                    try
                    {
                        WavMethods.waveInClose(m_pWavDevHandle);
                    }
                    catch
                    {
                        Debug.WriteLine("WaveIn.Dispose() - WavMethods.waveInClose()");
                    }
                    finally
                    {
                        m_pInDevice     = null;
                        m_pWavDevHandle = IntPtr.Zero;
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("WaveIn.Dispose() - " + ex.Message);
                }
            }
            m_IsDisposed = true;
        }
Exemplo n.º 9
0
        /// <summary>
        /// Gets audio output volume.
        /// </summary>
        /// <param name="left">Left channel volume level.</param>
        /// <param name="right">Right channel volume level.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        public void GetVolume(ref ushort left, ref ushort right)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException("WaveOut");
            }

            int volume = 0;

            WavMethods.waveOutGetVolume(m_pWavDevHandle, out volume);

            left  = (ushort)(volume & 0x0000ffff);
            right = (ushort)(volume >> 16);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="outputDevice">Output device.</param>
        /// <param name="samplesPerSec">Sample rate, in samples per second (hertz). For PCM common values are
        /// 8.0 kHz, 11.025 kHz, 22.05 kHz, and 44.1 kHz.</param>
        /// <param name="bitsPerSample">Bits per sample. For PCM 8 or 16 are the only valid values.</param>
        /// <param name="channels">Number of channels.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>outputDevice</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the aruments has invalid value.</exception>
        public WaveOut(WavOutDevice outputDevice, int samplesPerSec, int bitsPerSample, int channels)
        {
            if (outputDevice == null)
            {
                throw new ArgumentNullException("outputDevice");
            }
            if (samplesPerSec < 8000)
            {
                throw new ArgumentException("Argument 'samplesPerSec' value must be >= 8000.");
            }
            if (bitsPerSample < 8)
            {
                throw new ArgumentException("Argument 'bitsPerSample' value must be >= 8.");
            }
            if (channels < 1)
            {
                throw new ArgumentException("Argument 'channels' value must be >= 1.");
            }

            m_pOutDevice    = outputDevice;
            m_SamplesPerSec = samplesPerSec;
            m_BitsPerSample = bitsPerSample;
            m_Channels      = channels;
            m_BlockSize     = m_Channels * (m_BitsPerSample / 8);
            m_pPlayItems    = new List <PlayItem>();

            // Try to open wav device.
            WAVEFORMATEX format = new WAVEFORMATEX();

            format.wFormatTag     = WavFormat.PCM;
            format.nChannels      = (ushort)m_Channels;
            format.nSamplesPerSec = (uint)samplesPerSec;
            //1秒钟数据量(字节/秒)= (采样频率(Hz)*采样位数(bit)*声道数)/ 8
            //换算成20ms的数据量则再除50
            format.nAvgBytesPerSec = (uint)((m_SamplesPerSec * m_Channels * (m_BitsPerSample / 8))) / 50;

            format.nBlockAlign    = (ushort)m_BlockSize;
            format.wBitsPerSample = (ushort)m_BitsPerSample;
            format.cbSize         = 0;

            m_MinBuffer = (int)format.nAvgBytesPerSec * 10;
            // We must delegate reference, otherwise GC will collect it.
            m_pWaveOutProc = new waveOutProc(this.OnWaveOutProc);
            int result = WavMethods.waveOutOpen(out m_pWavDevHandle, m_pOutDevice.Index, format, m_pWaveOutProc, 0, WavConstants.CALLBACK_FUNCTION);

            if (result != MMSYSERR.NOERROR)
            {
                throw new Exception("Failed to open wav device, error: " + result.ToString() + ".");
            }
        }
Exemplo n.º 11
0
 /// <summary>
 /// Cleans up the first data block in play queue.
 /// </summary>
 /// <param name="state">User data.</param>
 private void OnCleanUpFirstBlock(object state)
 {
     try{
         lock (m_pPlayItems){
             PlayItem item = m_pPlayItems[0];
             WavMethods.waveOutUnprepareHeader(m_pWavDevHandle, item.HeaderHandle.AddrOfPinnedObject(), Marshal.SizeOf(item.Header));
             m_pPlayItems.Remove(item);
             m_BytesBuffered -= item.DataSize;
             item.Dispose();
         }
     }
     catch {
     }
 }
Exemplo n.º 12
0
        /// <summary>
        /// Stops recording.
        /// </summary>
        public void Stop()
        {
            if (!m_IsRecording)
            {
                return;
            }
            m_IsRecording = false;

            int result = WavMethods.waveInStop(m_pWavDevHandle);

            if (result != MMSYSERR.NOERROR)
            {
                throw new Exception("Failed to stop wav device, error: " + result + ".");
            }
        }
Exemplo n.º 13
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="outputDevice">Input device.</param>
        /// <param name="samplesPerSec">Sample rate, in samples per second (hertz). For PCM common values are
        /// 8.0 kHz, 11.025 kHz, 22.05 kHz, and 44.1 kHz.</param>
        /// <param name="bitsPerSample">Bits per sample. For PCM 8 or 16 are the only valid values.</param>
        /// <param name="channels">Number of channels.</param>
        /// <param name="bufferSize">Specifies recording buffer size.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>outputDevice</b> is null.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the aruments has invalid value.</exception>
        public WaveIn(WavInDevice device, int samplesPerSec, int bitsPerSample, int channels, int bufferSize)
        {
            if (device == null)
            {
                throw new ArgumentNullException("device");
            }
            if (samplesPerSec < 8000)
            {
                throw new ArgumentException("Argument 'samplesPerSec' value must be >= 8000.");
            }
            if (bitsPerSample < 8)
            {
                throw new ArgumentException("Argument 'bitsPerSample' value must be >= 8.");
            }
            if (channels < 1)
            {
                throw new ArgumentException("Argument 'channels' value must be >= 1.");
            }

            m_pInDevice     = device;
            m_SamplesPerSec = samplesPerSec;
            m_BitsPerSample = bitsPerSample;
            m_Channels      = channels;
            m_BufferSize    = bufferSize;
            m_BlockSize     = m_Channels * (m_BitsPerSample / 8);
            m_pBuffers      = new List <BufferItem>();

            // Try to open wav device.
            WAVEFORMATEX format = new WAVEFORMATEX();

            format.wFormatTag      = WavFormat.PCM;
            format.nChannels       = (ushort)m_Channels;
            format.nSamplesPerSec  = (uint)samplesPerSec;
            format.nAvgBytesPerSec = (uint)(m_SamplesPerSec * m_Channels * (m_BitsPerSample / 8));
            format.nBlockAlign     = (ushort)m_BlockSize;
            format.wBitsPerSample  = (ushort)m_BitsPerSample;
            format.cbSize          = 0;
            // We must delegate reference, otherwise GC will collect it.
            m_pWaveInProc = new waveInProc(this.OnWaveInProc);
            int result = WavMethods.waveInOpen(out m_pWavDevHandle, m_pInDevice.Index, format, m_pWaveInProc, 0, WavConstants.CALLBACK_FUNCTION);

            if (result != MMSYSERR.NOERROR)
            {
                throw new Exception("Failed to open wav device, error: " + result.ToString() + ".");
            }

            EnsureBuffers();
        }
Exemplo n.º 14
0
        /// <summary>
        /// Processes first first filled buffer in queue and disposes it if done.
        /// </summary>
        /// <param name="state">User data.</param>
        private void ProcessFirstBuffer(object state)
        {
            if (m_IsRecording)
            {
                BufferItem item;
                try
                {
                    lock (m_pBuffers)
                    {
                        item = m_pBuffers[0];

                        // Raise BufferFull event.
                        OnBufferFull(item.Data);

                        // Clean up.
                        try
                        {
                            Debug.WriteLine("WaveIn.ProcessFirstBuffer() - waveInUnprepareHeader");
                            WavMethods.waveInUnprepareHeader(m_pWavDevHandle, item.HeaderHandle.AddrOfPinnedObject(), Marshal.SizeOf(item.Header));
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine("WaveIn.ProcessFirstBuffer() - WavMethods.waveInUnprepareHeader - " + ex.Message);
                        }
                        finally
                        {
                            m_pBuffers.RemoveAt(0);
                            Debug.WriteLine("WaveIn.ProcessFirstBuffer() - cleanup buffers");
                            item.Dispose();
                        }
                    }

                    Debug.WriteLine("WaveIn.ProcessFirstBuffer() - EnsureBuffers()");
                    EnsureBuffers();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine("WaveIn.ProcessFirstBuffer() - " + ex.Message);
                }
            }
        }
Exemplo n.º 15
0
        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.");
            }
            while (m_pPlayItems.Count > 10)
            {
                Thread.Sleep(10);
            }
            byte[] data = new byte[count];
            Array.Copy(audioData, offset, data, 0, count);
            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.waveOutPrepareHeader(m_pWavDevHandle, headerHandle.AddrOfPinnedObject(), Marshal.SizeOf(wavHeader));

            if (result == MMSYSERR.NOERROR)
            {
                PlayItem item = new PlayItem(ref headerHandle, ref dataHandle, data.Length);
                lock (m_pPlayItems) {
                    m_pPlayItems.Add(item);
                    m_BytesBuffered += data.Length;

                    if (m_BytesBuffered < m_MinBuffer / 10)
                    {
                        if (!m_IsBuffing)
                        {
                            WavMethods.waveOutPause(m_pWavDevHandle);
                            m_IsBuffing = true;
                        }
                    }
                    else if (m_IsBuffing && m_BytesBuffered > m_MinBuffer)
                    {
                        WavMethods.waveOutRestart(m_pWavDevHandle);
                        m_IsBuffing = false;
                    }



                    result = WavMethods.waveOutWrite(m_pWavDevHandle, headerHandle.AddrOfPinnedObject(), Marshal.SizeOf(wavHeader));
                }
            }
            else
            {
                dataHandle.Free();
                headerHandle.Free();
            }
            //--------------------------------------------------------------------------------------------------
        }
Exemplo n.º 16
0
        /// <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();
            }
            //--------------------------------------------------------------------------------------------------
        }