Code:
/ DotNET / DotNET / 8.0 / untmp / 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 [....] 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.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UseLicense.cs
- DataSysAttribute.cs
- RepeatBehaviorConverter.cs
- XmlElementCollection.cs
- IdentityReference.cs
- TransactedReceiveData.cs
- DataStorage.cs
- ExtractedStateEntry.cs
- RawKeyboardInputReport.cs
- SocketElement.cs
- GeneralTransformGroup.cs
- InputLanguageCollection.cs
- DiagnosticTraceSchemas.cs
- XmlObjectSerializerReadContext.cs
- AppModelKnownContentFactory.cs
- DBSqlParserColumn.cs
- ObservableDictionary.cs
- WebServiceErrorEvent.cs
- DataContractSerializerElement.cs
- StatusBarItem.cs
- OperationCanceledException.cs
- Attributes.cs
- AbstractSvcMapFileLoader.cs
- DataGridViewCellValueEventArgs.cs
- DataFormat.cs
- ListBox.cs
- ArrayExtension.cs
- SmtpCommands.cs
- WorkflowInstance.cs
- X509Logo.cs
- SessionEndingEventArgs.cs
- ToolStripDropDownMenu.cs
- ActiveDocumentEvent.cs
- QuaternionAnimationBase.cs
- ConvertEvent.cs
- EventsTab.cs
- DecimalAnimationUsingKeyFrames.cs
- SrgsGrammar.cs
- RequiredFieldValidator.cs
- IdleTimeoutMonitor.cs
- PriorityItem.cs
- ProtocolProfile.cs
- MetadataArtifactLoaderComposite.cs
- DataGridPagerStyle.cs
- KeyPullup.cs
- TextureBrush.cs
- XmlSchemaCompilationSettings.cs
- MemoryRecordBuffer.cs
- DefaultValueAttribute.cs
- TreeWalkHelper.cs
- User.cs
- ResourcesGenerator.cs
- XmlToDatasetMap.cs
- SqlDataSourceQuery.cs
- CompositeCollectionView.cs
- JoinElimination.cs
- ZeroOpNode.cs
- Property.cs
- MsmqChannelFactory.cs
- DataViewManager.cs
- BrushConverter.cs
- DefaultTextStore.cs
- ScriptModule.cs
- ZipIOFileItemStream.cs
- DbConnectionPoolOptions.cs
- CommandManager.cs
- Knowncolors.cs
- SetterBase.cs
- ClientCultureInfo.cs
- IdentifierService.cs
- OrCondition.cs
- SystemColors.cs
- DeferredSelectedIndexReference.cs
- SignedPkcs7.cs
- printdlgexmarshaler.cs
- CompensationHandlingFilter.cs
- FreezableDefaultValueFactory.cs
- DataGridViewAutoSizeColumnsModeEventArgs.cs
- DBSqlParserColumn.cs
- Rect.cs
- SystemIcmpV4Statistics.cs
- ConvertEvent.cs
- MetadataImporter.cs
- ContentValidator.cs
- _BufferOffsetSize.cs
- Visitor.cs
- WindowsSecurityTokenAuthenticator.cs
- SingleAnimationBase.cs
- Animatable.cs
- BaseTemplateBuildProvider.cs
- Rights.cs
- DesignerActionUIStateChangeEventArgs.cs
- MediaScriptCommandRoutedEventArgs.cs
- URLIdentityPermission.cs
- Serializer.cs
- NativeMethods.cs
- EmptyEnumerable.cs
- Convert.cs
- HtmlToClrEventProxy.cs
- DebugHandleTracker.cs