AudioDeviceOut.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Speech / Src / Internal / Synthesis / AudioDeviceOut.cs / 1 / AudioDeviceOut.cs

                            //------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
//  This class defines the header used to identify a waveform-audio
//  buffer. 
// 
// History:
//		2/1/2005	jeanfp		Created from the Sapi Managed code 
//-----------------------------------------------------------------

using System;
using System.Collections.Generic; 
using System.Runtime.InteropServices;
using System.Threading; 
using System.Diagnostics; 

namespace System.Speech.Internal.Synthesis 
{
    /// 
    /// Encapsulates Waveform Audio Interface playback functions and provides a simple
    /// interface for playing audio. 
    /// 
    internal class AudioDeviceOut : AudioBase, IDisposable 
    { 
        //*******************************************************************
        // 
        // Constructors
        //
        //*******************************************************************
 
        #region Constructors
 
        ///  
        /// Create an instance of AudioDeviceOut.
        ///  
        internal AudioDeviceOut (int curDevice, IAsyncDispatch asyncDispatch)
        {
            _delegate = new SafeNativeMethods.WaveOutProc (CallBackProc);
            _asyncDispatch = asyncDispatch; 
            _curDevice = curDevice;
        } 
 
        ~AudioDeviceOut ()
        { 
            Dispose (false);
        }

        ///  
        /// TODOC
        ///  
        public void Dispose () 
        {
            Dispose (true); 
            GC.SuppressFinalize (this);
        }

        private void Dispose (bool disposing) 
        {
            if (_deviceOpen && _hwo != IntPtr.Zero) 
            { 
                SafeNativeMethods.waveOutClose (_hwo);
                _deviceOpen = false; 
            }
            if (disposing)
            {
                ((IDisposable) _evt).Dispose (); 
            }
        } 
 
        #endregion
 
        //********************************************************************
        //
        // Internal Methods
        // 
        //*******************************************************************
 
        #region Internal Methods 

        #region AudioDevice implementation 

        /// 
        /// Begin to play
        ///  
        /// 
        override internal void Begin (byte [] wfx) 
        { 
            if (_deviceOpen)
            { 
                System.Diagnostics.Debug.Assert (false);
                throw new InvalidOperationException ();
            }
 
            // Get the alignments values
            WAVEFORMATEX.AvgBytesPerSec (wfx, out _nAvgBytesPerSec, out _blockAlign); 
 
            MMSYSERR result;
            lock (_noWriteOutLock) 
            {
                result = SafeNativeMethods.waveOutOpen (ref _hwo, _curDevice, wfx, _delegate, IntPtr.Zero, SafeNativeMethods.CALLBACK_FUNCTION);

                if (_fPaused && result == MMSYSERR.NOERROR) 
                {
                    result = SafeNativeMethods.waveOutPause (_hwo); 
                } 
                // set the flags
                _aborted = false; 
                _deviceOpen = true;
            }

            if (result != MMSYSERR.NOERROR) 
            {
                throw new AudioException (result); 
            } 

            // Reset the counter for the number of bytes written so far 
            _bytesWritten = 0;

            // Nothing in the queue
            _evt.Set (); 

        } 
 
        /// 
        /// Begin to play 
        /// 
        override internal void End ()
        {
            if (!_deviceOpen) 
            {
                System.Diagnostics.Debug.Assert (false); 
                throw new InvalidOperationException (); 
            }
            lock (_noWriteOutLock) 
            {
                _deviceOpen = false;

                MMSYSERR result; 

                CheckForAbort (); 
 
                if (_queueIn.Count != 0)
                { 
                    SafeNativeMethods.waveOutReset (_hwo);
                }

                // Close it; no point in returning errors if this fails 
                result = SafeNativeMethods.waveOutClose (_hwo);
 
                if (result != MMSYSERR.NOERROR) 
                {
                    // This may create a dead lock 
                    System.Diagnostics.Debug.Assert (false);
                }
            }
        } 

        ///  
        /// Play a wave file. 
        /// 
        ///  
        override internal void Play (byte [] buffer)
        {
            if (!_deviceOpen)
            { 
                System.Diagnostics.Debug.Assert (false);
            } 
            else 
            {
                int bufferSize = buffer.Length; 
                _bytesWritten += bufferSize;

                System.Diagnostics.Debug.Assert (bufferSize % _blockAlign == 0);
 
                WaveHeader waveHeader = new WaveHeader (buffer);
                GCHandle waveHdr = waveHeader.WAVEHDR; 
                MMSYSERR result = SafeNativeMethods.waveOutPrepareHeader (_hwo, waveHdr.AddrOfPinnedObject (), waveHeader.SizeHDR); 

                if (result != MMSYSERR.NOERROR) 
                {
                    throw new AudioException (result);
                }
 
                lock (_noWriteOutLock)
                { 
                    if (!_aborted) 
                    {
                        lock (_queueIn) 
                        {
                            InItem item = new InItem (waveHeader);

                            _queueIn.Add (item); 

                            // Something in the queue cannot exit anymore 
                            _evt.Reset (); 
                        }
 
                        // Start playback of the first buffer
                        result = SafeNativeMethods.waveOutWrite (_hwo, waveHdr.AddrOfPinnedObject (), waveHeader.SizeHDR);
                        if (result != MMSYSERR.NOERROR)
                        { 
                            lock (_queueIn)
                            { 
                                _queueIn.RemoveAt (_queueIn.Count - 1); 
                                throw new AudioException (result);
                            } 
                        }
                    }
                }
            } 
        }
 
 
        /// 
        /// Pause the playback of a sound. 
        /// 
        /// MMSYSERR.NOERROR if successful
        override internal void Pause ()
        { 
            lock (_noWriteOutLock)
            { 
                if (!_aborted && !_fPaused) 
                {
                    if (_deviceOpen) 
                    {
                        MMSYSERR result = SafeNativeMethods.waveOutPause (_hwo);
                        if (result != MMSYSERR.NOERROR)
                        { 
                            System.Diagnostics.Debug.Assert (false, ((int) result).ToString (System.Globalization.CultureInfo.InvariantCulture));
                        } 
                    } 
                    _fPaused = true;
                } 
            }
        }

        ///  
        /// Resume the playback of a paused sound.
        ///  
        /// MMSYSERR.NOERROR if successful 
        override internal void Resume ()
        { 
            lock (_noWriteOutLock)
            {
                if (!_aborted && _fPaused)
                { 
                    if (_deviceOpen)
                    { 
                        MMSYSERR result = SafeNativeMethods.waveOutRestart (_hwo); 
                        if (result != MMSYSERR.NOERROR)
                        { 
                            System.Diagnostics.Debug.Assert (false);
                        }
                    }
                } 
            }
            _fPaused = false; 
        } 

        ///  
        /// Wait for all the queued buffers to be played
        /// 
        override internal void Abort ()
        { 
            lock (_noWriteOutLock)
            { 
                _aborted = true; 
                if (_queueIn.Count > 0)
                { 
                    SafeNativeMethods.waveOutReset (_hwo);
                    _evt.WaitOne ();
                }
            } 
        }
 
        override internal void InjectEvent (TTSEvent ttsEvent) 
        {
            if (_asyncDispatch != null && !_aborted) 
            {
                lock (_queueIn)
                {
                    // Throw immediately if the queue is empty 
                    if (_queueIn.Count == 0)
                    { 
                        _asyncDispatch.Post (ttsEvent); 
                    }
                    else 
                    {
                        // Will be thrown before the next write to the audio device
                        _queueIn.Add (new InItem (ttsEvent));
                    } 
                }
            } 
        } 

        ///  
        /// Wait for all the queued buffers to be played
        /// 
        override internal void WaitUntilDone ()
        { 
            if (!_deviceOpen)
            { 
                System.Diagnostics.Debug.Assert (false); 
                throw new InvalidOperationException ();
            } 

            _evt.WaitOne ();
        }
 
        #endregion
 
        #region Audio device specific methods 

#if unused_yet 

        /// 
        /// Get the volume of this sound.
        ///  
        /// Left channel volume level
        /// Right channel volume level 
        /// MMSYSERR.NOERROR if successful 
        internal MMSYSERR GetVolume (ref ushort volLeft, ref ushort volRight)
        { 
            uint vol = 0;

            MMSYSERR result = SafeNativeMethods.waveOutGetVolume (_hwo, ref vol);
            if (result != MMSYSERR.NOERROR) 
            {
                throw new AudioException (result); 
            } 

            volLeft = (ushort) (vol & 0x0000ffff); 
            volRight = (ushort) (vol >> 16);

            return MMSYSERR.NOERROR;
        } 

        ///  
        /// Sets the volume of this sound. 
        /// 
        /// Left channel volume level 
        /// Right channel volume level
        /// MMSYSERR.NOERROR if successful
        internal void SetVolume (ushort volLeft, ushort volRight)
        { 
            uint vol = ((uint) volLeft & 0x0000ffff) | ((uint) volRight << 16);
            MMSYSERR result = SafeNativeMethods.waveOutSetVolume (_hwo, vol); 
            { 
                throw new AudioException (result);
            } 
        }

#endif
        ///  
        ///  Determine the number of available playback devices.
        ///  
        /// Number of output devices 
        internal static int NumDevices ()
        { 
            return SafeNativeMethods.waveOutGetNumDevs ();
        }

        internal static int GetDevicedId (string name) 
        {
            for (int iDevice = 0; iDevice < NumDevices (); iDevice++) 
            { 
                string device;
                if (GetDeviceName (iDevice, out device) == MMSYSERR.NOERROR && string.Compare (device, name, StringComparison.OrdinalIgnoreCase) == 0) 
                {
                    return iDevice;
                }
            } 
            return -1;
        } 
 
        /// 
        /// Get the name of the specified playback device. 
        /// 
        /// ID of the device
        /// Destination string assigned the name
        /// MMSYSERR.NOERROR if successful 
        internal static MMSYSERR GetDeviceName (int deviceId, [MarshalAs (UnmanagedType.LPWStr)] out string prodName)
        { 
            prodName = string.Empty; 
            SafeNativeMethods.WAVEOUTCAPS caps = new SafeNativeMethods.WAVEOUTCAPS ();
 
            MMSYSERR result = SafeNativeMethods.waveOutGetDevCaps ((IntPtr) deviceId, ref caps, Marshal.SizeOf (caps));
            if (result != MMSYSERR.NOERROR)
            {
                return result; 
            }
 
            prodName = caps.szPname; 

            return MMSYSERR.NOERROR; 
        }

        #endregion
 
        #endregion
 
        //******************************************************************** 
        //
        // Internal Fields 
        //
        //********************************************************************

        #region Internal Fields 

        override internal TimeSpan Duration 
        { 
            get
            { 
                if (_nAvgBytesPerSec == 0)
                {
                    return new TimeSpan (0);
                } 
                return new TimeSpan ((_bytesWritten * TimeSpan.TicksPerSecond) / _nAvgBytesPerSec);
            } 
        } 

        #endregion 

        //*******************************************************************
        //
        // Private Methods 
        //
        //******************************************************************** 
 
        #region Private Methods
 
        private void CallBackProc (IntPtr hwo, MM_MSG uMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2)
        {
            if (uMsg == MM_MSG.MM_WOM_DONE)
            { 
                InItem inItem;
                lock (_queueIn) 
                { 
                    inItem = _queueIn [0];
                    inItem.ReleaseData (); 
                    _queueIn.RemoveAt (0);
                    _queueOut.Add (inItem);

                    // look for the next elements in the queue if they are events to throw! 
                    while (_queueIn.Count > 0)
                    { 
                        inItem = _queueIn [0]; 
                        // Do we have an event or a sound buffer
                        if (inItem._waveHeader == null) 
                        {
                            if (_asyncDispatch != null && !_aborted)
                            {
                                _asyncDispatch.Post (inItem._userData); 
                            }
                            _queueIn.RemoveAt (0); 
                        } 
                        else
                        { 
                            break;
                        }
                    }
                } 

                // if the queue is empty, then restart the callers thread 
                if (_queueIn.Count == 0) 
                {
                    _evt.Set (); 
                }

            }
        } 

        private void ClearBuffers () 
        { 
            foreach (InItem item in _queueOut)
            { 
                WaveHeader waveHeader = item._waveHeader;
                MMSYSERR result;

                result = SafeNativeMethods.waveOutUnprepareHeader (_hwo, waveHeader.WAVEHDR. 
AddrOfPinnedObject (), waveHeader.SizeHDR);
                if (result != MMSYSERR.NOERROR) 
                { 
                    //System.Diagnostics.Debug.Assert (false);
                } 
            }
        }

        private void CheckForAbort () 
        {
            if (_aborted) 
            { 
                // Synchronous operation
                lock (_queueIn) 
                {
                    foreach (InItem inItem in _queueIn)
                    {
                        // Do we have an event or a sound buffer 
                        if (inItem._waveHeader != null)
                        { 
                            WaveHeader waveHeader = inItem._waveHeader; 
                            SafeNativeMethods.waveOutUnprepareHeader (_hwo, waveHeader.WAVEHDR.AddrOfPinnedObject (), waveHeader.SizeHDR);
                        } 
                        else
                        {
                            _asyncDispatch.Post (inItem._userData);
                        } 
                    }
                    _queueIn.Clear (); 
 
                    // if the queue is empty, then restart the callers thread
                    _evt.Set (); 
                }
            }
            ClearBuffers ();
        } 

        #endregion 
 
        //*******************************************************************
        // 
        // Private Types
        //
        //*******************************************************************
 
        #region Private Types
 
        ///  
        /// This object must keet a reference to the waveHeader object
        /// so that the pinned buffer containing the data is not 
        /// released before it is finished being played
        /// 
        private class InItem : IDisposable
        { 
            internal InItem (WaveHeader waveHeader)
            { 
                _waveHeader = waveHeader; 
            }
 
            internal InItem (object userData)
            {
                _userData = userData;
            } 

            ///  
            /// TODOC 
            /// 
            public void Dispose () 
            {
                if (_waveHeader != null)
                {
                    _waveHeader.Dispose (); 
                }
            } 
 
            internal void ReleaseData ()
            { 
                if (_waveHeader != null)
                {
                    _waveHeader.ReleaseData ();
                } 
            }
 
            internal WaveHeader _waveHeader; 
            internal object _userData;
        } 

        #endregion

        //******************************************************************* 
        //
        // Private Fields 
        // 
        //********************************************************************
 
        #region Private Fields

        private List _queueIn = new List ();
 
        private List _queueOut = new List ();
 
        private int _blockAlign; 
        private int _bytesWritten;
        private int _nAvgBytesPerSec; 

        private IntPtr _hwo;

        private int _curDevice; 

        private ManualResetEvent _evt = new ManualResetEvent (false); 
 
        private SafeNativeMethods.WaveOutProc _delegate;
 
        private IAsyncDispatch _asyncDispatch;

        private bool _deviceOpen;
        private object _noWriteOutLock = new object (); 
        private bool _fPaused;
 
        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
//  This class defines the header used to identify a waveform-audio
//  buffer. 
// 
// History:
//		2/1/2005	jeanfp		Created from the Sapi Managed code 
//-----------------------------------------------------------------

using System;
using System.Collections.Generic; 
using System.Runtime.InteropServices;
using System.Threading; 
using System.Diagnostics; 

namespace System.Speech.Internal.Synthesis 
{
    /// 
    /// Encapsulates Waveform Audio Interface playback functions and provides a simple
    /// interface for playing audio. 
    /// 
    internal class AudioDeviceOut : AudioBase, IDisposable 
    { 
        //*******************************************************************
        // 
        // Constructors
        //
        //*******************************************************************
 
        #region Constructors
 
        ///  
        /// Create an instance of AudioDeviceOut.
        ///  
        internal AudioDeviceOut (int curDevice, IAsyncDispatch asyncDispatch)
        {
            _delegate = new SafeNativeMethods.WaveOutProc (CallBackProc);
            _asyncDispatch = asyncDispatch; 
            _curDevice = curDevice;
        } 
 
        ~AudioDeviceOut ()
        { 
            Dispose (false);
        }

        ///  
        /// TODOC
        ///  
        public void Dispose () 
        {
            Dispose (true); 
            GC.SuppressFinalize (this);
        }

        private void Dispose (bool disposing) 
        {
            if (_deviceOpen && _hwo != IntPtr.Zero) 
            { 
                SafeNativeMethods.waveOutClose (_hwo);
                _deviceOpen = false; 
            }
            if (disposing)
            {
                ((IDisposable) _evt).Dispose (); 
            }
        } 
 
        #endregion
 
        //********************************************************************
        //
        // Internal Methods
        // 
        //*******************************************************************
 
        #region Internal Methods 

        #region AudioDevice implementation 

        /// 
        /// Begin to play
        ///  
        /// 
        override internal void Begin (byte [] wfx) 
        { 
            if (_deviceOpen)
            { 
                System.Diagnostics.Debug.Assert (false);
                throw new InvalidOperationException ();
            }
 
            // Get the alignments values
            WAVEFORMATEX.AvgBytesPerSec (wfx, out _nAvgBytesPerSec, out _blockAlign); 
 
            MMSYSERR result;
            lock (_noWriteOutLock) 
            {
                result = SafeNativeMethods.waveOutOpen (ref _hwo, _curDevice, wfx, _delegate, IntPtr.Zero, SafeNativeMethods.CALLBACK_FUNCTION);

                if (_fPaused && result == MMSYSERR.NOERROR) 
                {
                    result = SafeNativeMethods.waveOutPause (_hwo); 
                } 
                // set the flags
                _aborted = false; 
                _deviceOpen = true;
            }

            if (result != MMSYSERR.NOERROR) 
            {
                throw new AudioException (result); 
            } 

            // Reset the counter for the number of bytes written so far 
            _bytesWritten = 0;

            // Nothing in the queue
            _evt.Set (); 

        } 
 
        /// 
        /// Begin to play 
        /// 
        override internal void End ()
        {
            if (!_deviceOpen) 
            {
                System.Diagnostics.Debug.Assert (false); 
                throw new InvalidOperationException (); 
            }
            lock (_noWriteOutLock) 
            {
                _deviceOpen = false;

                MMSYSERR result; 

                CheckForAbort (); 
 
                if (_queueIn.Count != 0)
                { 
                    SafeNativeMethods.waveOutReset (_hwo);
                }

                // Close it; no point in returning errors if this fails 
                result = SafeNativeMethods.waveOutClose (_hwo);
 
                if (result != MMSYSERR.NOERROR) 
                {
                    // This may create a dead lock 
                    System.Diagnostics.Debug.Assert (false);
                }
            }
        } 

        ///  
        /// Play a wave file. 
        /// 
        ///  
        override internal void Play (byte [] buffer)
        {
            if (!_deviceOpen)
            { 
                System.Diagnostics.Debug.Assert (false);
            } 
            else 
            {
                int bufferSize = buffer.Length; 
                _bytesWritten += bufferSize;

                System.Diagnostics.Debug.Assert (bufferSize % _blockAlign == 0);
 
                WaveHeader waveHeader = new WaveHeader (buffer);
                GCHandle waveHdr = waveHeader.WAVEHDR; 
                MMSYSERR result = SafeNativeMethods.waveOutPrepareHeader (_hwo, waveHdr.AddrOfPinnedObject (), waveHeader.SizeHDR); 

                if (result != MMSYSERR.NOERROR) 
                {
                    throw new AudioException (result);
                }
 
                lock (_noWriteOutLock)
                { 
                    if (!_aborted) 
                    {
                        lock (_queueIn) 
                        {
                            InItem item = new InItem (waveHeader);

                            _queueIn.Add (item); 

                            // Something in the queue cannot exit anymore 
                            _evt.Reset (); 
                        }
 
                        // Start playback of the first buffer
                        result = SafeNativeMethods.waveOutWrite (_hwo, waveHdr.AddrOfPinnedObject (), waveHeader.SizeHDR);
                        if (result != MMSYSERR.NOERROR)
                        { 
                            lock (_queueIn)
                            { 
                                _queueIn.RemoveAt (_queueIn.Count - 1); 
                                throw new AudioException (result);
                            } 
                        }
                    }
                }
            } 
        }
 
 
        /// 
        /// Pause the playback of a sound. 
        /// 
        /// MMSYSERR.NOERROR if successful
        override internal void Pause ()
        { 
            lock (_noWriteOutLock)
            { 
                if (!_aborted && !_fPaused) 
                {
                    if (_deviceOpen) 
                    {
                        MMSYSERR result = SafeNativeMethods.waveOutPause (_hwo);
                        if (result != MMSYSERR.NOERROR)
                        { 
                            System.Diagnostics.Debug.Assert (false, ((int) result).ToString (System.Globalization.CultureInfo.InvariantCulture));
                        } 
                    } 
                    _fPaused = true;
                } 
            }
        }

        ///  
        /// Resume the playback of a paused sound.
        ///  
        /// MMSYSERR.NOERROR if successful 
        override internal void Resume ()
        { 
            lock (_noWriteOutLock)
            {
                if (!_aborted && _fPaused)
                { 
                    if (_deviceOpen)
                    { 
                        MMSYSERR result = SafeNativeMethods.waveOutRestart (_hwo); 
                        if (result != MMSYSERR.NOERROR)
                        { 
                            System.Diagnostics.Debug.Assert (false);
                        }
                    }
                } 
            }
            _fPaused = false; 
        } 

        ///  
        /// Wait for all the queued buffers to be played
        /// 
        override internal void Abort ()
        { 
            lock (_noWriteOutLock)
            { 
                _aborted = true; 
                if (_queueIn.Count > 0)
                { 
                    SafeNativeMethods.waveOutReset (_hwo);
                    _evt.WaitOne ();
                }
            } 
        }
 
        override internal void InjectEvent (TTSEvent ttsEvent) 
        {
            if (_asyncDispatch != null && !_aborted) 
            {
                lock (_queueIn)
                {
                    // Throw immediately if the queue is empty 
                    if (_queueIn.Count == 0)
                    { 
                        _asyncDispatch.Post (ttsEvent); 
                    }
                    else 
                    {
                        // Will be thrown before the next write to the audio device
                        _queueIn.Add (new InItem (ttsEvent));
                    } 
                }
            } 
        } 

        ///  
        /// Wait for all the queued buffers to be played
        /// 
        override internal void WaitUntilDone ()
        { 
            if (!_deviceOpen)
            { 
                System.Diagnostics.Debug.Assert (false); 
                throw new InvalidOperationException ();
            } 

            _evt.WaitOne ();
        }
 
        #endregion
 
        #region Audio device specific methods 

#if unused_yet 

        /// 
        /// Get the volume of this sound.
        ///  
        /// Left channel volume level
        /// Right channel volume level 
        /// MMSYSERR.NOERROR if successful 
        internal MMSYSERR GetVolume (ref ushort volLeft, ref ushort volRight)
        { 
            uint vol = 0;

            MMSYSERR result = SafeNativeMethods.waveOutGetVolume (_hwo, ref vol);
            if (result != MMSYSERR.NOERROR) 
            {
                throw new AudioException (result); 
            } 

            volLeft = (ushort) (vol & 0x0000ffff); 
            volRight = (ushort) (vol >> 16);

            return MMSYSERR.NOERROR;
        } 

        ///  
        /// Sets the volume of this sound. 
        /// 
        /// Left channel volume level 
        /// Right channel volume level
        /// MMSYSERR.NOERROR if successful
        internal void SetVolume (ushort volLeft, ushort volRight)
        { 
            uint vol = ((uint) volLeft & 0x0000ffff) | ((uint) volRight << 16);
            MMSYSERR result = SafeNativeMethods.waveOutSetVolume (_hwo, vol); 
            { 
                throw new AudioException (result);
            } 
        }

#endif
        ///  
        ///  Determine the number of available playback devices.
        ///  
        /// Number of output devices 
        internal static int NumDevices ()
        { 
            return SafeNativeMethods.waveOutGetNumDevs ();
        }

        internal static int GetDevicedId (string name) 
        {
            for (int iDevice = 0; iDevice < NumDevices (); iDevice++) 
            { 
                string device;
                if (GetDeviceName (iDevice, out device) == MMSYSERR.NOERROR && string.Compare (device, name, StringComparison.OrdinalIgnoreCase) == 0) 
                {
                    return iDevice;
                }
            } 
            return -1;
        } 
 
        /// 
        /// Get the name of the specified playback device. 
        /// 
        /// ID of the device
        /// Destination string assigned the name
        /// MMSYSERR.NOERROR if successful 
        internal static MMSYSERR GetDeviceName (int deviceId, [MarshalAs (UnmanagedType.LPWStr)] out string prodName)
        { 
            prodName = string.Empty; 
            SafeNativeMethods.WAVEOUTCAPS caps = new SafeNativeMethods.WAVEOUTCAPS ();
 
            MMSYSERR result = SafeNativeMethods.waveOutGetDevCaps ((IntPtr) deviceId, ref caps, Marshal.SizeOf (caps));
            if (result != MMSYSERR.NOERROR)
            {
                return result; 
            }
 
            prodName = caps.szPname; 

            return MMSYSERR.NOERROR; 
        }

        #endregion
 
        #endregion
 
        //******************************************************************** 
        //
        // Internal Fields 
        //
        //********************************************************************

        #region Internal Fields 

        override internal TimeSpan Duration 
        { 
            get
            { 
                if (_nAvgBytesPerSec == 0)
                {
                    return new TimeSpan (0);
                } 
                return new TimeSpan ((_bytesWritten * TimeSpan.TicksPerSecond) / _nAvgBytesPerSec);
            } 
        } 

        #endregion 

        //*******************************************************************
        //
        // Private Methods 
        //
        //******************************************************************** 
 
        #region Private Methods
 
        private void CallBackProc (IntPtr hwo, MM_MSG uMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2)
        {
            if (uMsg == MM_MSG.MM_WOM_DONE)
            { 
                InItem inItem;
                lock (_queueIn) 
                { 
                    inItem = _queueIn [0];
                    inItem.ReleaseData (); 
                    _queueIn.RemoveAt (0);
                    _queueOut.Add (inItem);

                    // look for the next elements in the queue if they are events to throw! 
                    while (_queueIn.Count > 0)
                    { 
                        inItem = _queueIn [0]; 
                        // Do we have an event or a sound buffer
                        if (inItem._waveHeader == null) 
                        {
                            if (_asyncDispatch != null && !_aborted)
                            {
                                _asyncDispatch.Post (inItem._userData); 
                            }
                            _queueIn.RemoveAt (0); 
                        } 
                        else
                        { 
                            break;
                        }
                    }
                } 

                // if the queue is empty, then restart the callers thread 
                if (_queueIn.Count == 0) 
                {
                    _evt.Set (); 
                }

            }
        } 

        private void ClearBuffers () 
        { 
            foreach (InItem item in _queueOut)
            { 
                WaveHeader waveHeader = item._waveHeader;
                MMSYSERR result;

                result = SafeNativeMethods.waveOutUnprepareHeader (_hwo, waveHeader.WAVEHDR. 
AddrOfPinnedObject (), waveHeader.SizeHDR);
                if (result != MMSYSERR.NOERROR) 
                { 
                    //System.Diagnostics.Debug.Assert (false);
                } 
            }
        }

        private void CheckForAbort () 
        {
            if (_aborted) 
            { 
                // Synchronous operation
                lock (_queueIn) 
                {
                    foreach (InItem inItem in _queueIn)
                    {
                        // Do we have an event or a sound buffer 
                        if (inItem._waveHeader != null)
                        { 
                            WaveHeader waveHeader = inItem._waveHeader; 
                            SafeNativeMethods.waveOutUnprepareHeader (_hwo, waveHeader.WAVEHDR.AddrOfPinnedObject (), waveHeader.SizeHDR);
                        } 
                        else
                        {
                            _asyncDispatch.Post (inItem._userData);
                        } 
                    }
                    _queueIn.Clear (); 
 
                    // if the queue is empty, then restart the callers thread
                    _evt.Set (); 
                }
            }
            ClearBuffers ();
        } 

        #endregion 
 
        //*******************************************************************
        // 
        // Private Types
        //
        //*******************************************************************
 
        #region Private Types
 
        ///  
        /// This object must keet a reference to the waveHeader object
        /// so that the pinned buffer containing the data is not 
        /// released before it is finished being played
        /// 
        private class InItem : IDisposable
        { 
            internal InItem (WaveHeader waveHeader)
            { 
                _waveHeader = waveHeader; 
            }
 
            internal InItem (object userData)
            {
                _userData = userData;
            } 

            ///  
            /// TODOC 
            /// 
            public void Dispose () 
            {
                if (_waveHeader != null)
                {
                    _waveHeader.Dispose (); 
                }
            } 
 
            internal void ReleaseData ()
            { 
                if (_waveHeader != null)
                {
                    _waveHeader.ReleaseData ();
                } 
            }
 
            internal WaveHeader _waveHeader; 
            internal object _userData;
        } 

        #endregion

        //******************************************************************* 
        //
        // Private Fields 
        // 
        //********************************************************************
 
        #region Private Fields

        private List _queueIn = new List ();
 
        private List _queueOut = new List ();
 
        private int _blockAlign; 
        private int _bytesWritten;
        private int _nAvgBytesPerSec; 

        private IntPtr _hwo;

        private int _curDevice; 

        private ManualResetEvent _evt = new ManualResetEvent (false); 
 
        private SafeNativeMethods.WaveOutProc _delegate;
 
        private IAsyncDispatch _asyncDispatch;

        private bool _deviceOpen;
        private object _noWriteOutLock = new object (); 
        private bool _fPaused;
 
        #endregion 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK