/// <summary> /// Initialises the WaveOut device /// </summary> /// <param name="waveProvider">WaveProvider to play</param> public void Init(IWaveProvider waveProvider) { if (playbackState != PlaybackState.Stopped) { throw new InvalidOperationException("Can't re-initialize during playback"); } if (hWaveOut != IntPtr.Zero) { // normally we don't allow calling Init twice, but as experiment, see if we can clean up and go again // try to allow reuse of this waveOut device // n.b. risky if Playback thread has not exited DisposeBuffers(); CloseWaveOut(); } this.callbackEvent = new AutoResetEvent(false); this.waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize((DesiredLatency + NumberOfBuffers - 1) / NumberOfBuffers); MmResult result; lock (waveOutLock) { result = WaveInterop.waveOutOpenWindow(out hWaveOut, (IntPtr)DeviceNumber, waveStream.WaveFormat, callbackEvent.SafeWaitHandle.DangerousGetHandle(), IntPtr.Zero, WaveInterop.WaveInOutOpenFlags.CallbackEvent); } MmException.Try(result, "waveOutOpen"); buffers = new WaveOutBuffer[NumberOfBuffers]; playbackState = PlaybackState.Stopped; for (int n = 0; n < NumberOfBuffers; n++) { buffers[n] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } }
/// <summary> /// Initialises the WaveOut device /// </summary> /// <param name="waveProvider">Wave provider to play</param> public void Init(IWaveProvider waveProvider) { if (Thread.CurrentThread.ManagedThreadId != waveOutThread.ManagedThreadId) { lock (actionQueue) { actionQueue.Enqueue(new WaveOutAction(WaveOutFunction.Init, waveStream)); workAvailable.Set(); } return; } waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize(desiredLatency); //waveStream.GetReadSize((desiredLatency + 2) / 3); numBuffers = 3; MmException.Try( WaveInterop.waveOutOpen(out hWaveOut, (IntPtr)devNumber, waveStream.WaveFormat, callback, IntPtr.Zero, WaveInterop.CallbackFunction), "waveOutOpen"); buffers = new WaveOutBuffer[numBuffers]; playbackState = PlaybackState.Stopped; var waveOutLock = new object(); for (int n = 0; n < numBuffers; n++) { buffers[n] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } }
/// <summary> /// Init the wave provider. /// </summary> private void Init() { // Create the channels SampleChannel channel = new SampleChannel(_audioReader, true); MeteringSampleProvider provider = new MeteringSampleProvider(channel); // Create the wave provider. _waveProvider = new SampleToWaveProvider(provider); // calculate the buffer size. int bufferSize = _waveProvider.WaveFormat.ConvertLatencyToByteSize((DesiredLatency + NumberOfBuffers - 1) / NumberOfBuffers); MmResult result; lock (_waveOutLock) { result = _callbackInfo.WaveOutOpen(out _hWaveOut, _device.Index, _waveProvider.WaveFormat, _callback); } MmException.Try(result, "waveOutOpen"); _buffers = new WaveOutBuffer[NumberOfBuffers]; _playbackState = PlaybackState.Stopped; for (int n = 0; n < NumberOfBuffers; n++) { _buffers[n] = new WaveOutBuffer(_hWaveOut, bufferSize, _waveProvider, _waveOutLock); } }
private void OnBufferDone(WaveOutBuffer buffer) { if (playbackState == PlaybackState.Playing) { if (!buffer.OnDone()) { playbackState = PlaybackState.Stopped; RaisePlaybackStopped(); } } }
void CreateBuffers(int buffersCount, int bufferLength) { for (int i = 0; i < buffersCount; i++) { WaveOutBuffer buffer = new WaveOutBuffer(bufferLength); buffer._hdr.dwBufferLength = bufferLength; int result = Native.waveOutPrepareHeader(_hWaveout, buffer._gchHdr.AddrOfPinnedObject(), Marshal.SizeOf(buffer._hdr)); System.Diagnostics.Debug.Assert(result == Native.MMSYSERR_NOERROR); _buffers.Add(buffer); } }
void ReleaseBuffers() { for (int i = 0; i < _buffers.Count; i++) { WaveOutBuffer buffer = _buffers[i]; int result = Native.waveOutUnprepareHeader(_hWaveout, buffer._gchHdr.AddrOfPinnedObject(), Marshal.SizeOf(buffer._hdr)); System.Diagnostics.Debug.Assert(result == Native.MMSYSERR_NOERROR); buffer.Dispose(); } _buffers.Clear(); }
/// <summary> /// Made non-static so that playing can be stopped here /// </summary> /// <param name="hWaveOut"></param> /// <param name="uMsg"></param> /// <param name="dwInstance"></param> /// <param name="wavhdr"></param> /// <param name="dwReserved"></param> private void Callback(IntPtr hWaveOut, WaveMessage uMsg, IntPtr dwInstance, WaveHeader wavhdr, IntPtr dwReserved) { if (uMsg == WaveMessage.WaveOutDone) { GCHandle hBuffer = (GCHandle)wavhdr.userData; WaveOutBuffer buffer = (WaveOutBuffer)hBuffer.Target; Interlocked.Decrement(ref _queuedBuffers); Exception exception = null; // check that we're not here through pressing stop if (PlaybackState == PlaybackState.Playing) { // to avoid deadlocks in Function callback mode, // we lock round this whole thing, which will include the // reading from the stream. // this protects us from calling waveOutReset on another // thread while a WaveOutWrite is in progress lock (_waveOutLock) { try { if (buffer.OnDone()) { Interlocked.Increment(ref _queuedBuffers); } } catch (Exception e) { // one likely cause is soundcard being unplugged exception = e; } } } if (_queuedBuffers == 0) { if (_callbackInfo.Strategy == WaveCallbackStrategy.FunctionCallback && _playbackState == PlaybackState.Stopped) { // the user has pressed stop // DO NOT raise the playback stopped event from here // since on the main thread we are still in the waveOutReset function // Playback stopped will be raised elsewhere } else { // set explicitly for when we reach the end of the audio. _playbackState = PlaybackState.Stopped; RaisePlaybackStoppedEvent(exception, (_pressStop ? false : true)); } } } }
internal static void WaveOutProc(IntPtr hdrvr, int uMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2) { if (uMsg == Native.MM_WOM_DONE) { try { System.Diagnostics.Debug.Assert(dwInstance != IntPtr.Zero); WinMMAudioRender instance = (WinMMAudioRender)((GCHandle)dwInstance).Target; System.Diagnostics.Debug.Assert(dwParam1 != IntPtr.Zero); Native.WAVEHDR hdr = (Native.WAVEHDR)Marshal.PtrToStructure(dwParam1, typeof(Native.WAVEHDR)); System.Diagnostics.Debug.Assert(hdr.dwUser != IntPtr.Zero); WaveOutBuffer waveOutBuffer = (WaveOutBuffer)((GCHandle)hdr.dwUser).Target; if (hdr.dwBufferLength > 0) { instance._totalDuration += hdr.dwBufferLength; instance._callback.PlaybackProgress(instance._totalDuration, hdr.dwBufferLength, instance._fmt.nAvgBytesPerSec); } // if we are still playing get a new audio buffer if (instance._started) { int length = 0; if (instance._callback.NextAudioBuffer(waveOutBuffer._data, ref length)) { System.Diagnostics.Debug.Assert(length <= waveOutBuffer._data.Length); waveOutBuffer._hdr.dwBufferLength = length; int result = Native.waveOutWrite(instance._hWaveout, waveOutBuffer._gchHdr.AddrOfPinnedObject(), Marshal.SizeOf(waveOutBuffer._hdr)); System.Diagnostics.Debug.Assert(result == Native.MMSYSERR_NOERROR); } else { // end of stream read instance._started = false; } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); } } }
/// <summary> /// Initialises the WaveOut device /// </summary> /// <param name="waveProvider">WaveProvider to play</param> public void Init(IWaveProvider waveProvider) { this.waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize((DesiredLatency + NumberOfBuffers - 1) / NumberOfBuffers); MmResult result; lock (waveOutLock) { result = callbackInfo.WaveOutOpen(out hWaveOut, DeviceNumber, waveStream.WaveFormat, callback); } MmException.Try(result, "waveOutOpen"); buffers = new WaveOutBuffer[NumberOfBuffers]; playbackState = PlaybackState.Stopped; for (int n = 0; n < NumberOfBuffers; n++) { buffers[n] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } }
/// <summary> /// Initialises the WaveOut device /// </summary> /// <param name="waveProvider">WaveProvider to play</param> public void Init(IWaveProvider waveProvider) { this.waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize((DesiredLatency + NumberOfBuffers - 1) / NumberOfBuffers); MmResult result; lock (waveOutLock) { result = callbackInfo.WaveOutOpen(out hWaveOut, DeviceNumber, waveStream.WaveFormat, callback); } MmException.Try(result, "waveOutOpen"); buffers = new WaveOutBuffer[NumberOfBuffers]; playbackState = PlaybackState.Stopped; for (int n = 0; n < NumberOfBuffers; n++) { buffers[n] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } }
public bool Start(WinMMAudioRenderCallback callback, int sampleRate, int channels, int bitsPerSample) { if (null == callback) { return(false); } if ((0 == sampleRate) || (0 == channels) || (0 == bitsPerSample)) { return(false); } // only mono and stereo are supported if (channels > 2) { return(false); } Stop(); _callback = callback; _fmt = new Native.WAVEFORMATEX(); _fmt.wFormatTag = Native.WAVE_FORMAT_PCM; _fmt.nChannels = (short)channels; _fmt.nSamplesPerSec = sampleRate; _fmt.nBlockAlign = (short)((bitsPerSample >> 3) * channels); _fmt.nAvgBytesPerSec = _fmt.nBlockAlign * sampleRate; _fmt.wBitsPerSample = (short)bitsPerSample; _fmt.cbSize = (short)Marshal.SizeOf(_fmt); _gchThis = GCHandle.Alloc(this); int result = Native.waveOutOpen(out _hWaveout, Native.WAVE_MAPPER, _fmt, _waveOutProc, (IntPtr)_gchThis, Native.CALLBACK_FUNCTION); if (result != Native.MMSYSERR_NOERROR) { _gchThis.Free(); _hWaveout = IntPtr.Zero; return(false); } _started = true; _totalDuration = 0; CreateBuffers(5, _fmt.nBlockAlign * (_fmt.nSamplesPerSec / 50)); // 5 buffers, 20ms each buffer result = Native.waveOutPause(_hWaveout); System.Diagnostics.Debug.Assert(result == Native.MMSYSERR_NOERROR); // write the empty buffers for (int i = 0; i < _buffers.Count; i++) { WaveOutBuffer buffer = _buffers[i]; buffer._hdr.dwBufferLength = 0; result = Native.waveOutWrite(_hWaveout, buffer._gchHdr.AddrOfPinnedObject(), Marshal.SizeOf(buffer._hdr)); System.Diagnostics.Debug.Assert(Native.MMSYSERR_NOERROR == result); } result = Native.waveOutRestart(_hWaveout); System.Diagnostics.Debug.Assert(result == Native.MMSYSERR_NOERROR); return(true); }
/// <summary> /// Initialises the WaveOut device /// </summary> /// <param name="waveProvider">WaveProvider to play</param> public void Init(IWaveProvider waveProvider) { if (playbackState != PlaybackState.Stopped) { throw new InvalidOperationException("Can't re-initialize during playback"); } if (hWaveOut != IntPtr.Zero) { // normally we don't allow calling Init twice, but as experiment, see if we can clean up and go again // try to allow reuse of this waveOut device // n.b. risky if Playback thread has not exited DisposeBuffers(); CloseWaveOut(); } this.callbackEvent = new AutoResetEvent(false); this.waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize((DesiredLatency + NumberOfBuffers - 1) / NumberOfBuffers); MmResult result; lock (waveOutLock) { result = WaveInterop.waveOutOpenWindow(out hWaveOut, (IntPtr)DeviceNumber, waveStream.WaveFormat, callbackEvent.SafeWaitHandle.DangerousGetHandle(), IntPtr.Zero, WaveInterop.WaveInOutOpenFlags.CallbackEvent); } MmException.Try(result, "waveOutOpen"); buffers = new WaveOutBuffer[NumberOfBuffers]; playbackState = PlaybackState.Stopped; for (int n = 0; n < NumberOfBuffers; n++) { buffers[n] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } }