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
- SerializerProvider.cs
- CodeMethodInvokeExpression.cs
- RouteParametersHelper.cs
- InternalSafeNativeMethods.cs
- AdapterDictionary.cs
- LinkedResourceCollection.cs
- BaseValidator.cs
- ControlIdConverter.cs
- ImageListImage.cs
- SoapIncludeAttribute.cs
- XmlValidatingReaderImpl.cs
- HighContrastHelper.cs
- PropertyToken.cs
- FileStream.cs
- ConstraintEnumerator.cs
- TrustLevel.cs
- StyleHelper.cs
- ReflectionTypeLoadException.cs
- HttpResponseHeader.cs
- PropertyMetadata.cs
- OdbcConnectionFactory.cs
- RegexCode.cs
- IdentitySection.cs
- LinearQuaternionKeyFrame.cs
- SimpleHandlerBuildProvider.cs
- elementinformation.cs
- TextBoxRenderer.cs
- GPRECTF.cs
- UserControl.cs
- WebControlToolBoxItem.cs
- FamilyMapCollection.cs
- Compiler.cs
- DocumentCollection.cs
- AuthenticationServiceManager.cs
- TwoPhaseCommitProxy.cs
- InstancePersistenceException.cs
- TableLayout.cs
- EncryptedData.cs
- SystemWebCachingSectionGroup.cs
- SchemaHelper.cs
- ResourceDescriptionAttribute.cs
- activationcontext.cs
- ConfigurationManagerHelperFactory.cs
- CopyOnWriteList.cs
- XmlValidatingReader.cs
- SQLMembershipProvider.cs
- WebControlsSection.cs
- SelectionListDesigner.cs
- ReferencedType.cs
- ExcCanonicalXml.cs
- CharStorage.cs
- Point3DIndependentAnimationStorage.cs
- WebPartZone.cs
- SmtpLoginAuthenticationModule.cs
- ResourceKey.cs
- SQLSingleStorage.cs
- CatalogPart.cs
- ClientSettingsSection.cs
- AuthorizationPolicyTypeElementCollection.cs
- MetadataItemCollectionFactory.cs
- EnglishPluralizationService.cs
- DataGridViewRowEventArgs.cs
- OrderByBuilder.cs
- CalendarItem.cs
- BasicCellRelation.cs
- Substitution.cs
- XmlILAnnotation.cs
- ImportFileRequest.cs
- InputProcessorProfiles.cs
- Walker.cs
- filewebresponse.cs
- CommentAction.cs
- XmlNodeChangedEventArgs.cs
- OverflowException.cs
- TextElement.cs
- ProfileManager.cs
- DataBindingList.cs
- StreamAsIStream.cs
- XslVisitor.cs
- StreamGeometry.cs
- MemberExpression.cs
- CodeSubDirectoriesCollection.cs
- TextElementEditingBehaviorAttribute.cs
- SubtreeProcessor.cs
- TargetFrameworkUtil.cs
- Matrix3DStack.cs
- FilterUserControlBase.cs
- GacUtil.cs
- ScriptingScriptResourceHandlerSection.cs
- ComponentEvent.cs
- ItemList.cs
- GorillaCodec.cs
- JournalEntryListConverter.cs
- CompensationDesigner.cs
- CustomLineCap.cs
- ModelFunctionTypeElement.cs
- EntityViewGenerationAttribute.cs
- SqlDataSourceCache.cs
- TextEditorLists.cs
- DataRecordInfo.cs