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
- IpcChannelHelper.cs
- ExpressionVisitor.cs
- COM2Enum.cs
- NetWebProxyFinder.cs
- PolicyStatement.cs
- MetafileHeaderEmf.cs
- SqlConnectionPoolGroupProviderInfo.cs
- ConfigurationPropertyCollection.cs
- SecurityUtils.cs
- AddInBase.cs
- HtmlWindow.cs
- FunctionDetailsReader.cs
- MetadataItem_Static.cs
- OleDbMetaDataFactory.cs
- Pool.cs
- GcSettings.cs
- AuthenticationException.cs
- TextRangeSerialization.cs
- DataFormats.cs
- Byte.cs
- TransformDescriptor.cs
- ProtocolImporter.cs
- ManagedIStream.cs
- RadioButtonList.cs
- ConnectorSelectionGlyph.cs
- DocobjHost.cs
- Atom10FormatterFactory.cs
- WindowsAuthenticationModule.cs
- RbTree.cs
- IsolationInterop.cs
- LicenseManager.cs
- LineVisual.cs
- TextBox.cs
- BidirectionalDictionary.cs
- FixedSOMPageConstructor.cs
- MemoryMappedViewAccessor.cs
- DocumentsTrace.cs
- DecoderBestFitFallback.cs
- PeerTransportListenAddressValidator.cs
- ContainerUIElement3D.cs
- ICollection.cs
- EnumerableRowCollection.cs
- Range.cs
- ItemsPanelTemplate.cs
- ISCIIEncoding.cs
- HashMembershipCondition.cs
- ConfigurationManager.cs
- OneWayElement.cs
- MetaModel.cs
- PreviewPrintController.cs
- DataGridViewComboBoxColumn.cs
- TimeStampChecker.cs
- Axis.cs
- AxisAngleRotation3D.cs
- ComponentManagerBroker.cs
- SizeConverter.cs
- CodeDomSerializer.cs
- ExeContext.cs
- TypeHelpers.cs
- ClientSponsor.cs
- CheckableControlBaseAdapter.cs
- Button.cs
- DetailsViewDeletedEventArgs.cs
- CDSsyncETWBCLProvider.cs
- RegexGroupCollection.cs
- WebPartAuthorizationEventArgs.cs
- QueryExpr.cs
- ReadOnlyHierarchicalDataSource.cs
- DateTimePickerDesigner.cs
- xmlsaver.cs
- WindowVisualStateTracker.cs
- SystemIPInterfaceStatistics.cs
- TimeEnumHelper.cs
- BulletedListEventArgs.cs
- StringPropertyBuilder.cs
- GenericIdentity.cs
- WebPartZone.cs
- StylusCaptureWithinProperty.cs
- IPEndPointCollection.cs
- CreateUserWizard.cs
- SettingsProperty.cs
- FormViewRow.cs
- Events.cs
- NamespaceEmitter.cs
- MeshGeometry3D.cs
- ColorMap.cs
- BrowserDefinition.cs
- Binding.cs
- XPathDocumentIterator.cs
- DetailsViewRow.cs
- CorePropertiesFilter.cs
- ReaderContextStackData.cs
- SqlFlattener.cs
- ObjectDataSourceFilteringEventArgs.cs
- NonParentingControl.cs
- WizardPanel.cs
- ConfigPathUtility.cs
- TdsParser.cs
- documentsequencetextpointer.cs
- MissingSatelliteAssemblyException.cs