/// <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; } this.waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize(desiredLatency); //waveStream.GetReadSize((desiredLatency + 2) / 3); this.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; object waveOutLock = new object(); for (int n = 0; n < numBuffers; n++) { buffers[n] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } }
private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, IntPtr dwInstance, WaveHeader wavhdr, IntPtr dwReserved) { if (uMsg == WaveInterop.WaveMessage.WaveOutDone) { WaveOutBuffer waveOutBuffer = (WaveOutBuffer)((GCHandle)wavhdr.userData).Target; Interlocked.Decrement(ref this.queuedBuffers); Exception e = null; if (this.PlaybackState == PlaybackState.Playing) { lock (this.waveOutLock) { try { if (waveOutBuffer.OnDone()) { Interlocked.Increment(ref this.queuedBuffers); } } catch (Exception ex) { e = ex; } } } if (this.queuedBuffers == 0) { if (this.callbackInfo.Strategy == WaveCallbackStrategy.FunctionCallback && this.playbackState == PlaybackState.Stopped) { return; } this.playbackState = PlaybackState.Stopped; this.RaisePlaybackStoppedEvent(e); } } }
private void OnBufferDone(WaveOutBuffer buffer) { if (playbackState == PlaybackState.Playing) { if (!buffer.OnDone()) { playbackState = PlaybackState.Stopped; RaisePlaybackStopped(); } } }
// made non-static so that playing can be stopped here private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, IntPtr dwInstance, WaveHeader wavhdr, IntPtr dwReserved) { if (uMsg == WaveInterop.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 NAudioLogger.Instance.LogError(e.Message); exception = e; } } } if (queuedBuffers == 0) { if (callbackInfo.Strategy == WaveCallbackStrategy.FunctionCallback && playbackState == Wave.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 { playbackState = PlaybackState.Stopped; // set explicitly for when we reach the end of the audio RaisePlaybackStoppedEvent(exception); } } } }
// made non-static so that playing can be stopped here private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, IntPtr dwUser, WaveHeader wavhdr, IntPtr dwReserved) { if (uMsg == WaveInterop.WaveMessage.WaveOutDone) { // check that we're not here through pressing stop GCHandle hBuffer = (GCHandle)wavhdr.userData; WaveOutBuffer buffer = (WaveOutBuffer)hBuffer.Target; lock (actionQueue) { actionQueue.Enqueue(new WaveOutAction(WaveOutFunction.BufferDone, buffer)); workAvailable.Set(); } // n.b. this was wrapped in an exception handler, but bug should be fixed now } }
// made non-static so that playing can be stopped here private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, Int32 dwUser, WaveHeader wavhdr, int dwReserved) { if (uMsg == WaveInterop.WaveMessage.WaveOutDone) { GCHandle hBuffer = (GCHandle)wavhdr.userData; WaveOutBuffer buffer = (WaveOutBuffer)hBuffer.Target; // check that we're not here through pressing stop if (PlaybackState == PlaybackState.Playing) { if (!buffer.OnDone()) { playbackState = PlaybackState.Stopped; RaisePlaybackStoppedEvent(); } } // n.b. this was wrapped in an exception handler, but bug should be fixed now } }
/// <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 = 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">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); } }
// made non-static so that playing can be stopped here private void Callback(IntPtr hWaveOut, WaveInterop.WaveMessage uMsg, IntPtr dwInstance, WaveHeader wavhdr, IntPtr dwReserved) { if (uMsg == WaveInterop.WaveMessage.WaveOutDone) { GCHandle hBuffer = (GCHandle)wavhdr.userData; WaveOutBuffer buffer = (WaveOutBuffer)hBuffer.Target; Interlocked.Decrement(ref queuedBuffers); // 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) { if (buffer.OnDone()) { Interlocked.Increment(ref queuedBuffers); } } } if (queuedBuffers == 0) { if (callbackInfo.Strategy == WaveCallbackStrategy.FunctionCallback && playbackState == Wave.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 { RaisePlaybackStoppedEvent(); } } // n.b. this was wrapped in an exception handler, but bug should be fixed now } }
/// <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; } this.waveStream = waveProvider; int bufferSize = waveProvider.WaveFormat.ConvertLatencyToByteSize(desiredLatency); //waveStream.GetReadSize((desiredLatency + 2) / 3); this.numBuffers = 3; MmException.Try(WaveInterop.waveOutOpen(out hWaveOut, devNumber, waveStream.WaveFormat, callback, 0, WaveInterop.CallbackFunction), "waveOutOpen"); buffers = new WaveOutBuffer[numBuffers]; playbackState = PlaybackState.Stopped; object waveOutLock = new object(); for (int n = 0; n < numBuffers; n++) { buffers[n] = new WaveOutBuffer(hWaveOut, bufferSize, waveStream, waveOutLock); } }