private async void PlayThread() { MediaFoundationResampler mediaFoundationResampler = null; IWaveProvider playbackProvider = this.sourceProvider; Exception exception = null; try { if (this.resamplerNeeded) { mediaFoundationResampler = new MediaFoundationResampler(sourceProvider, outputFormat); playbackProvider = mediaFoundationResampler; } // fill a whole buffer bufferFrameCount = audioClient.BufferSize; bytesPerFrame = outputFormat.Channels * outputFormat.BitsPerSample / 8; readBuffer = new byte[bufferFrameCount * bytesPerFrame]; FillBuffer(playbackProvider, bufferFrameCount); audioClient.Start(); while (playbackState != PlaybackState.Stopped) { // If using Event Sync, Wait for notification from AudioClient or Sleep half latency int timeout = 3 * latencyMilliseconds; var r = NativeMethods.WaitForSingleObjectEx(frameEventWaitHandle, timeout, true); if (r != 0) { throw new InvalidOperationException("Timed out waiting for event"); } // If still playing and notification is ok if (playbackState == PlaybackState.Playing) { // See how much buffer space is available. int numFramesPadding = 0; // In exclusive mode, always ask the max = bufferFrameCount = audioClient.BufferSize numFramesPadding = (shareMode == AudioClientShareMode.Shared) ? audioClient.CurrentPadding : 0; int numFramesAvailable = bufferFrameCount - numFramesPadding; if (numFramesAvailable > 0) { FillBuffer(playbackProvider, numFramesAvailable); } } } // play the buffer out while (audioClient.CurrentPadding > 0) { await Task.Delay(latencyMilliseconds / 2); } audioClient.Stop(); if (playbackState == PlaybackState.Stopped) { audioClient.Reset(); } } catch (Exception e) { exception = e; } finally { if (mediaFoundationResampler != null) { mediaFoundationResampler.Dispose(); } RaisePlaybackStopped(exception); } }
private async void PlayThread() { await Activate(); var playbackProvider = Init(); bool isClientRunning = false; try { if (this.resamplerNeeded) { var resampler = new WdlResamplingSampleProvider(playbackProvider.ToSampleProvider(), outputFormat.SampleRate); playbackProvider = new SampleToWaveProvider(resampler); } // fill a whole buffer bufferFrameCount = audioClient.BufferSize; bytesPerFrame = outputFormat.Channels * outputFormat.BitsPerSample / 8; //readBuffer = new byte[bufferFrameCount*bytesPerFrame]; int desiredReadLength = bufferFrameCount * bytesPerFrame; int providableReadLength = bufferFrameCount * playbackProvider.WaveFormat.Channels * playbackProvider.WaveFormat.BitsPerSample / 8; readBuffer = new byte[providableReadLength]; newReadBuffer = new byte[desiredReadLength > providableReadLength ? desiredReadLength : providableReadLength]; FillBuffer(playbackProvider, bufferFrameCount, outputFormat.Channels, playbackProvider.WaveFormat.Channels, playbackProvider.WaveFormat.BitsPerSample); int timeout = 3 * latencyMilliseconds; while (playbackState != WasapiOutState.Disposed) { if (playbackState != WasapiOutState.Playing) { playThreadEvent.WaitOne(500); } // If still playing and notification is ok if (playbackState == WasapiOutState.Playing) { if (!isClientRunning) { audioClient.Start(); isClientRunning = true; } // If using Event Sync, Wait for notification from AudioClient or Sleep half latency var r = NativeMethods.WaitForSingleObjectEx(frameEventWaitHandle, timeout, true); if (r != 0) { throw new InvalidOperationException("Timed out waiting for event"); } // See how much buffer space is available. int numFramesPadding = 0; // In exclusive mode, always ask the max = bufferFrameCount = audioClient.BufferSize numFramesPadding = (shareMode == AudioClientShareMode.Shared) ? audioClient.CurrentPadding : 0; int numFramesAvailable = bufferFrameCount - numFramesPadding; if (numFramesAvailable > 0) { FillBuffer(playbackProvider, numFramesAvailable, outputFormat.Channels, playbackProvider.WaveFormat.Channels, playbackProvider.WaveFormat.BitsPerSample); } } if (playbackState == WasapiOutState.Stopping) { // play the buffer out while (audioClient.CurrentPadding > 0) { await Task.Delay(latencyMilliseconds / 2); } audioClient.Stop(); isClientRunning = false; audioClient.Reset(); playbackState = WasapiOutState.Stopped; RaisePlaybackStopped(null); } if (playbackState == WasapiOutState.Disposing) { audioClient.Stop(); isClientRunning = false; audioClient.Reset(); playbackState = WasapiOutState.Disposed; var disposablePlaybackProvider = playbackProvider as IDisposable; if (disposablePlaybackProvider != null) { disposablePlaybackProvider.Dispose(); // do everything on this thread, even dispose in case it is Media Foundation } RaisePlaybackStopped(null); } } } catch (Exception e) { RaisePlaybackStopped(e); } finally { audioClient.Dispose(); audioClient = null; renderClient = null; NativeMethods.CloseHandle(frameEventWaitHandle); } }
private void DoRecording() { Debug.WriteLine("Recording buffer size: " + audioClient.BufferSize); var buf = new Byte[audioClient.BufferSize * bytesPerFrame]; int bufLength = 0; int minPacketSize = waveFormat.AverageBytesPerSecond / 100; //100ms try { AudioCaptureClient capture = audioClient.AudioCaptureClient; audioClient.Start(); int packetSize = capture.GetNextPacketSize(); while (captureState == WasapiCaptureState.Recording) { IntPtr pData = IntPtr.Zero; int numFramesToRead = 0; AudioClientBufferFlags dwFlags = 0; if (packetSize == 0) { if (NativeMethods.WaitForSingleObjectEx(hEvent, 100, true) != 0) { throw new Exception("Capture event timeout"); } } pData = capture.GetBuffer(out numFramesToRead, out dwFlags); if ((int)(dwFlags & AudioClientBufferFlags.Silent) > 0) { pData = IntPtr.Zero; } if (numFramesToRead == 0) { continue; } int capturedBytes = numFramesToRead * bytesPerFrame; if (pData == IntPtr.Zero) { Array.Clear(buf, bufLength, capturedBytes); } else { Marshal.Copy(pData, buf, bufLength, capturedBytes); } bufLength += capturedBytes; capture.ReleaseBuffer(numFramesToRead); if (bufLength >= minPacketSize) { if (DataAvailable != null) { DataAvailable(this, new WaveInEventArgs(buf, bufLength)); } bufLength = 0; } packetSize = capture.GetNextPacketSize(); } } catch (Exception ex) { RaiseRecordingStopped(ex); Debug.WriteLine("stop wasapi"); } finally { RaiseRecordingStopped(null); audioClient.Stop(); } Debug.WriteLine("stop wasapi"); }