private void InitializeInternal() { _audioClient = AudioClient.FromMMDevice(Device); _outputFormat = SetupWaveFormat(_source.WaveFormat, _audioClient); long latency = _latency * 10000; if (!_eventSync) { _audioClient.Initialize(_shareMode, AudioClientStreamFlags.None, latency, 0, _outputFormat, Guid.Empty); } else //event sync { if (_shareMode == AudioClientShareMode.Exclusive) //exclusive { _audioClient.Initialize(_shareMode, AudioClientStreamFlags.StreamFlags_EventCallback, latency, latency, _outputFormat, Guid.Empty); } else //shared { _audioClient.Initialize(_shareMode, AudioClientStreamFlags.StreamFlags_EventCallback, 0, 0, _outputFormat, Guid.Empty); _latency = (int)(_audioClient.StreamLatency / 10000); } _eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); _audioClient.SetEventHandle(_eventWaitHandle.SafeWaitHandle.DangerousGetHandle()); } _renderClient = AudioRenderClient.FromAudioClient(_audioClient); _simpleAudioVolume = SimpleAudioVolume.FromAudioClient(_audioClient); _simpleAudioVolume.MasterVolume = 1f; }
private void InitializeInternal() { const int reftimesPerMillisecond = 10000; _audioClient = AudioClient.FromMMDevice(Device); _outputFormat = SetupWaveFormat(_source, _audioClient); long latency = _latency * reftimesPerMillisecond; AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED_TRY_AGAIN: try { if (!_eventSync) { _audioClient.Initialize(_shareMode, AudioClientStreamFlags.None, latency, 0, _outputFormat, Guid.Empty); } else //event sync { if (_shareMode == AudioClientShareMode.Exclusive) //exclusive { _audioClient.Initialize(_shareMode, AudioClientStreamFlags.StreamFlagsEventCallback, latency, latency, _outputFormat, Guid.Empty); } else //shared { _audioClient.Initialize(_shareMode, AudioClientStreamFlags.StreamFlagsEventCallback, 0, 0, _outputFormat, Guid.Empty); //latency = (int)(_audioClient.StreamLatency / reftimesPerMillisecond); } } } catch (CoreAudioAPIException exception) { if (exception.ErrorCode == unchecked ((int)0x88890019)) //AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED { const long reftimesPerSec = 10000000; int framesInBuffer = _audioClient.GetBufferSize(); // ReSharper disable once PossibleLossOfFraction latency = (int)(reftimesPerSec * framesInBuffer / _outputFormat.SampleRate + 0.5); goto AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED_TRY_AGAIN; } throw; } if (_audioClient.StreamLatency != 0) //windows 10 returns zero, got no idea why => https://github.com/filoe/cscore/issues/11 { Latency = (int)(_audioClient.StreamLatency / reftimesPerMillisecond); } if (_eventSync) { _eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); _audioClient.SetEventHandle(_eventWaitHandle.SafeWaitHandle.DangerousGetHandle()); } _renderClient = AudioRenderClient.FromAudioClient(_audioClient); }
public void Dispose() { if (this.audioClient != null) { this.Stop(); this.audioClient.Dispose(); this.audioClient = null; this.renderClient = null; } }
public void CanPopulateABuffer() { AudioClient audioClient = InitializeClient(AudioClientShareMode.Shared); AudioRenderClient renderClient = audioClient.AudioRenderClient; int bufferFrameCount = audioClient.BufferSize; IntPtr buffer = renderClient.GetBuffer(bufferFrameCount); // TODO put some stuff in // will tell it it has a silent buffer renderClient.ReleaseBuffer(bufferFrameCount, AudioClientBufferFlags.Silent); }
public void CanCreateRenderClient() { using (var audioClient = Utils.CreateDefaultRenderClient()) { audioClient.Initialize(AudioClientShareMode.Shared, AudioClientStreamFlags.None, 1000, 0, audioClient.GetMixFormat(), Guid.Empty); using (var renderClient = AudioRenderClient.FromAudioClient(audioClient)) { Assert.IsNotNull(renderClient); } } }
/// <summary> /// Initialize for playing the specified wave stream /// </summary> /// <param name="waveProvider">IWaveProvider to play</param> public void Initialize(IWaveProvider waveProvider) { long latencyRefTimes = latencyMilliseconds * 10000; outputFormat = waveProvider.WaveFormat; var approFormat = audioClient.CheckSupportFormat(shareMode, outputFormat); // 規定フォーマットが対応しているかどうかのCheck. if (approFormat != null) { // 対応していない場合は、システムから提示のあった近似フォーマットで再度確認する。 if (!audioClient.IsFormatSupported(shareMode, approFormat)) { throw new ArgumentException("Unsupported Wave Format"); } outputFormat = approFormat; } //audioClient.Initialize(shareMode, EAudioClientStreamFlags.None, 1000000, 0, outputFormat, Guid.Empty); //ResamplerStream = new ResamplerDmoStream(waveProvider, outputFormat); //this.sourceProvider = ResamplerStream; //this.sourceProvider = waveProvider; this.sourceProvider = new ResampleWaveProvider(waveProvider, outputFormat); // If using EventSync, setup is specific with shareMode if (isUsingEventSync) { // Init Shared or Exclusive if (shareMode == EAudioClientShareMode.Shared) { // With EventCallBack and Shared, both latencies must be set to 0 audioClient.Initialize(shareMode, EAudioClientStreamFlags.EventCallback, 0, 0, outputFormat, Guid.Empty); // Get back the effective latency from AudioClient latencyMilliseconds = (int)(audioClient.StreamLatency / 10000); } else { // With EventCallBack and Exclusive, both latencies must equals audioClient.Initialize(shareMode, EAudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, outputFormat, Guid.Empty); } // Create the Wait Event Handle frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); audioClient.SetEventHandle(frameEventWaitHandle); } else { // Normal setup for both sharedMode audioClient.Initialize(shareMode, EAudioClientStreamFlags.None, latencyRefTimes, 0, outputFormat, Guid.Empty); } Debug.WriteLine(string.Format("RenderAudioClient: {0}", audioClient.ToString())); // Get the RenderClient renderClient = audioClient.AudioRenderClient; }
/// <summary> /// Dispose /// </summary> public void Dispose() { if (audioClient != null) { Stop(); audioClient.Dispose(); audioClient = null; renderClient = null; } }
/// <summary> /// Dispose /// </summary> public void Dispose() { if (audioClient != null) { Stop(); audioClient.Dispose(); audioClient = null; renderClient = null; NativeMethods.CloseHandle(frameEventWaitHandle); } }
/// <summary> /// Initialize for playing the specified format /// </summary> private void Init() { if (inited) { return; } long latencyRefTimes = latencyMilliseconds * 10000; // first attempt uses the WaveFormat from the WaveStream // If using EventSync, setup is specific with shareMode if (isUsingEventSync) { // Init Shared or Exclusive if (shareMode == AudioClientShareMode.Shared) { // With EventCallBack and Shared, both latencies must be set to 0 audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, 0, outputFormat, Guid.Empty); // Get back the effective latency from AudioClient // This is all wrong! it should be treated differently // latencyMilliseconds = (int)(audioClient.StreamLatency / 10000); } else { // With EventCallBack and Exclusive, both latencies must equals audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, outputFormat, Guid.Empty); } // Create the Wait Event Handle frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); audioClient.SetEventHandle(frameEventWaitHandle); } else { // Normal setup for both sharedMode audioClient.Initialize(shareMode, AudioClientStreamFlags.None, latencyRefTimes, 0, outputFormat, Guid.Empty); } waitHandles = new WaitHandle[] { frameEventWaitHandle }; // Get the RenderClient renderClient = audioClient.AudioRenderClient; inited = true; }
private bool FeedBuffer(AudioRenderClient renderClient, byte[] buffer, int numFramesCount, int frameSize) { //calculate the number of bytes to "feed" int count = numFramesCount * frameSize; count -= (count % _source.WaveFormat.BlockAlign); //if the driver did not request enough data, return true to continue playback if (count <= 0) { return(true); } //get the requested data int read = _source.Read(buffer, 0, count); //if the source did not provide enough data, we abort the playback by returning false if (read <= 0) { return(false); } //calculate the number of FRAMES to request int actualNumFramesCount = read / frameSize; //again there are some special requirements for exclusive mode AND eventsync if (_shareMode == AudioClientShareMode.Exclusive && _eventSync && read < count) { /* The caller can request a packet size that is less than or equal to the amount * of available space in the buffer (except in the case of an exclusive-mode stream * that uses event-driven buffering; for more information, see IAudioClient::Initialize). * see https://msdn.microsoft.com/en-us/library/windows/desktop/dd368243%28v=vs.85%29.aspx - remarks*/ //since we have to provide exactly the requested number of frames, we clear the rest of the array Array.Clear(buffer, read, count - read); //set the number of frames to request memory for, to the number of requested frames actualNumFramesCount = numFramesCount; } IntPtr ptr = renderClient.GetBuffer(actualNumFramesCount); //we may should introduce a try-finally statement here, but the Marshal.Copy method should not //throw any relevant exceptions ... so we should be able to always release the packet Marshal.Copy(buffer, 0, ptr, read); renderClient.ReleaseBuffer(actualNumFramesCount, AudioClientBufferFlags.None); return(true); }
/// <summary> /// Dispose /// </summary> public void Dispose() { if (audioClient != null) { Stop(); audioClient.Dispose(); audioClient = null; renderClient = null; } if (resamplerDmoStream != null) { resamplerDmoStream.Dispose(); resamplerDmoStream = null; } }
/// <summary> /// Init the output audio device /// </summary> /// <param name="waveProvider">waveProvider interface</param> public async Task Init(IWaveProvider waveProvider) { if (this.device == null) { // try our hardest to get a divice if the string is null or empty await GetDefaultAudioEndpoint(); NativeMethods.WaitForSingleObjectEx(initSync, 1000, true); } if (this.device != null) { try { await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async() => { try { this.EventWriterDLL.BuildLine("+1 start => WasapiOutRT::Init2 => called"); this.renderWaveFormat = waveProvider.WaveFormat; await Activate(); this.EventWriterDLL.BuildLine("+8 start => WasapiOutRT::Init2 => resampler not needed"); this.sourceProvider = waveProvider; // Get the RenderClient this.audioRenderClient = audioClient.AudioRenderClient; this.waitingForInitToFinish = false; this.EventWriterDLL.BuildLine("+9 start => WasapiOutRT::Init2 => finished"); } catch (Exception ex) { this.EventWriterDLL.WriteLine(Utils.EventWriterDLL.SeverityTypes.Error, 0x01, "WasapiOutRT::Init2 => Exception: " + ex.Message); } }); } catch (Exception ex) { Debug.WriteLine("Exception in WasapiOutRT, waveProvider = " + waveProvider.ToString() + ", " + ex.Message); this.EventWriterDLL.WriteLine(EventWriterDLL.SeverityTypes.Error, 0x01, "WasapiOutRT::Init2 => waveProvider = " + waveProvider.ToString() + ", exception: " + ex.Message); } } }
private bool FeedBuffer(AudioRenderClient renderClient, byte[] buffer, int numFramesCount, int frameSize) { int count = numFramesCount * frameSize; count -= (count % _source.WaveFormat.BlockAlign); if (count <= 0) { return(true); } int read = _source.Read(buffer, 0, count); var ptr = renderClient.GetBuffer(numFramesCount); Marshal.Copy(buffer, 0, ptr, read); renderClient.ReleaseBuffer((int)(read / frameSize), AudioClientBufferFlags.None); return(read > 0); }
private void CleanupResources(bool streamSwitch = false) { if (_createdResampler && _source is DmoResampler) { //dispose the source -> the volume source won't get touched //because of the interruption _source.Dispose(); _source = streamSwitch ? WrapVolumeSource(_volumeSource) : null; } if (_renderClient != null) { _renderClient.Dispose(); _renderClient = null; } if (_audioClient != null && _audioClient.BasePtr != IntPtr.Zero) { try { _audioClient.StopNative(); _audioClient.Reset(); } catch (CoreAudioAPIException ex) { if (ex.ErrorCode != unchecked ((int)0x88890001)) //AUDCLNT_E_NOT_INITIALIZED { throw; } } _audioClient.Dispose(); _audioClient = null; } if (_eventWaitHandle != null) { _eventWaitHandle.Close(); _eventWaitHandle = null; } TerminateStreamRouting(); _isInitialized = false; }
private void CleanupResources() { if (_createdResampler && _source is DmoResampler) { ((DmoResampler)_source).DisposeResamplerOnly(); _source = null; } if (_renderClient != null) { _renderClient.Dispose(); _renderClient = null; } if (_audioClient != null) { try { _audioClient.Reset(); } catch (CoreAudioAPIException ex) { if (ex.ErrorCode != unchecked ((int)0x88890001)) //AUDCLNT_E_NOT_INITIALIZED { throw; } } _audioClient.Dispose(); _audioClient = null; } if (_simpleAudioVolume != null) { _simpleAudioVolume.Dispose(); _simpleAudioVolume = null; } if (_eventWaitHandle != null) { _eventWaitHandle.Close(); _eventWaitHandle = null; } _isInitialized = false; }
/// <summary> /// Initialize for playing the specified wave stream /// </summary> private IWaveProvider Init() { var waveProvider = waveProviderFunc(); long latencyRefTimes = latencyMilliseconds * 10000; outputFormat = waveProvider.WaveFormat; // first attempt uses the WaveFormat from the WaveStream WaveFormatExtensible closestSampleRateFormat; if (!audioClient.IsFormatSupported(shareMode, outputFormat, out closestSampleRateFormat)) { // Use closesSampleRateFormat (in sharedMode, it equals usualy to the audioClient.MixFormat) // See documentation : http://msdn.microsoft.com/en-us/library/ms678737(VS.85).aspx // They say : "In shared mode, the audio engine always supports the mix format" // The MixFormat is more likely to be a WaveFormatExtensible. if (closestSampleRateFormat == null) { WaveFormat correctSampleRateFormat = audioClient.MixFormat; /*WaveFormat.CreateIeeeFloatWaveFormat( * audioClient.MixFormat.SampleRate, * audioClient.MixFormat.Channels);*/ if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { // Iterate from Worst to Best Format WaveFormatExtensible[] bestToWorstFormats = { new WaveFormatExtensible( outputFormat.SampleRate, 32, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 24, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 16, outputFormat.Channels), }; // Check from best Format to worst format ( Float32, Int24, Int16 ) for (int i = 0; i < bestToWorstFormats.Length; i++) { correctSampleRateFormat = bestToWorstFormats[i]; if (audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { break; } correctSampleRateFormat = null; } // If still null, then test on the PCM16, 2 channels if (correctSampleRateFormat == null) { // Last Last Last Chance (Thanks WASAPI) correctSampleRateFormat = new WaveFormatExtensible(outputFormat.SampleRate, 16, 2); if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { throw new NotSupportedException("Can't find a supported format to use"); } } } outputFormat = correctSampleRateFormat; } else { outputFormat = closestSampleRateFormat; } // just check that we can make it. //using (new MediaFoundationResampler(waveProvider, outputFormat)) { } this.resamplerNeeded = true; } else { resamplerNeeded = false; } // Init Shared or Exclusive if (shareMode == AudioClientShareMode.Shared) { // With EventCallBack and Shared, audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, 0, outputFormat, Guid.Empty); // Get back the effective latency from AudioClient. On Windows 10 it can be 0 if (audioClient.StreamLatency > 0) { latencyMilliseconds = (int)(audioClient.StreamLatency / 10000); } } else { // With EventCallBack and Exclusive, both latencies must equals audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, outputFormat, Guid.Empty); } // Create the Wait Event Handle frameEventWaitHandle = NativeMethods.CreateEventExW(IntPtr.Zero, IntPtr.Zero, 0, EventAccess.EVENT_ALL_ACCESS); audioClient.SetEventHandle(frameEventWaitHandle); // Get the RenderClient renderClient = audioClient.AudioRenderClient; return(waveProvider); }
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]; FillBuffer(playbackProvider, bufferFrameCount); 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); } } 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); } }
/// <summary> /// Initialize for playing the specified wave stream /// </summary> /// <param name="waveProvider">IWaveProvider to play</param> public void Init(IWaveProvider waveProvider) { long latencyRefTimes = latencyMilliseconds * 10000; outputFormat = waveProvider.WaveFormat; // first attempt uses the WaveFormat from the WaveStream WaveFormatExtensible closestSampleRateFormat; if (!audioClient.IsFormatSupported(shareMode, outputFormat, out closestSampleRateFormat)) { // Use closesSampleRateFormat (in sharedMode, it equals usualy to the audioClient.MixFormat) // See documentation : http://msdn.microsoft.com/en-us/library/ms678737(VS.85).aspx // They say : "In shared mode, the audio engine always supports the mix format" // The MixFormat is more likely to be a WaveFormatExtensible. if (closestSampleRateFormat == null) { WaveFormat correctSampleRateFormat = audioClient.MixFormat; /*WaveFormat.CreateIeeeFloatWaveFormat( * audioClient.MixFormat.SampleRate, * audioClient.MixFormat.Channels);*/ if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { // Iterate from Worst to Best Format WaveFormatExtensible[] bestToWorstFormats = { new WaveFormatExtensible( outputFormat.SampleRate, 32, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 24, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 16, outputFormat.Channels), }; // Check from best Format to worst format ( Float32, Int24, Int16 ) for (int i = 0; i < bestToWorstFormats.Length; i++) { correctSampleRateFormat = bestToWorstFormats[i]; if (audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { break; } correctSampleRateFormat = null; } // If still null and we're using exclusive mode, try to get the device format property. if (correctSampleRateFormat == null && shareMode == AudioClientShareMode.Exclusive) { // Based on https://stackoverflow.com/questions/22616924/wasapi-choosing-a-wave-format-for-exclusive-output byte[] waveFormatBytes = (byte[])mmDevice.Properties[PropertyKeys.PKEY_AudioEngine_DeviceFormat].Value; if (waveFormatBytes != null) { GCHandle handle = GCHandle.Alloc(waveFormatBytes, GCHandleType.Pinned); try { correctSampleRateFormat = (WaveFormatExtensible)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(WaveFormatExtensible)); } finally { handle.Free(); } } } // If still null, then test on the PCM16, 2 channels if (correctSampleRateFormat == null) { // Last Last Last Chance (Thanks WASAPI) correctSampleRateFormat = new WaveFormatExtensible(outputFormat.SampleRate, 16, 2); if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { throw new NotSupportedException("Can't find a supported format to use"); } } } outputFormat = correctSampleRateFormat; } else { outputFormat = closestSampleRateFormat; } // just check that we can make it. using (new ResamplerDmoStream(waveProvider, outputFormat)) { } dmoResamplerNeeded = true; } else { dmoResamplerNeeded = false; } sourceProvider = waveProvider; // If using EventSync, setup is specific with shareMode if (isUsingEventSync) { // Init Shared or Exclusive if (shareMode == AudioClientShareMode.Shared) { // With EventCallBack and Shared, both latencies must be set to 0 (update - not sure this is true anymore) // audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, 0, outputFormat, Guid.Empty); // Windows 10 returns 0 from stream latency, resulting in maxing out CPU usage later var streamLatency = audioClient.StreamLatency; if (streamLatency != 0) { // Get back the effective latency from AudioClient latencyMilliseconds = (int)(streamLatency / 10000); } } else { // With EventCallBack and Exclusive, both latencies must equals audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, outputFormat, Guid.Empty); } // Create the Wait Event Handle frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); audioClient.SetEventHandle(frameEventWaitHandle.SafeWaitHandle.DangerousGetHandle()); } else { // Normal setup for both sharedMode audioClient.Initialize(shareMode, AudioClientStreamFlags.None, latencyRefTimes, 0, outputFormat, Guid.Empty); } // Get the RenderClient renderClient = audioClient.AudioRenderClient; }
public void Init(IWaveProvider waveProvider) { long num = (long)(this.latencyMilliseconds * 10000); this.outputFormat = waveProvider.WaveFormat; WaveFormatExtensible waveFormatExtensible; if (!this.audioClient.IsFormatSupported(this.shareMode, this.outputFormat, out waveFormatExtensible)) { if (waveFormatExtensible == null) { WaveFormat waveFormat = this.audioClient.MixFormat; if (!this.audioClient.IsFormatSupported(this.shareMode, waveFormat)) { WaveFormatExtensible[] array = new WaveFormatExtensible[] { new WaveFormatExtensible(this.outputFormat.SampleRate, 32, this.outputFormat.Channels), new WaveFormatExtensible(this.outputFormat.SampleRate, 24, this.outputFormat.Channels), new WaveFormatExtensible(this.outputFormat.SampleRate, 16, this.outputFormat.Channels) }; for (int i = 0; i < array.Length; i++) { waveFormat = array[i]; if (this.audioClient.IsFormatSupported(this.shareMode, waveFormat)) { break; } waveFormat = null; } if (waveFormat == null) { waveFormat = new WaveFormatExtensible(this.outputFormat.SampleRate, 16, 2); if (!this.audioClient.IsFormatSupported(this.shareMode, waveFormat)) { throw new NotSupportedException("Can't find a supported format to use"); } } } this.outputFormat = waveFormat; } else { this.outputFormat = waveFormatExtensible; } using (new ResamplerDmoStream(waveProvider, this.outputFormat)) { } this.dmoResamplerNeeded = true; } else { this.dmoResamplerNeeded = false; } this.sourceProvider = waveProvider; if (this.isUsingEventSync) { if (this.shareMode == AudioClientShareMode.Shared) { this.audioClient.Initialize(this.shareMode, AudioClientStreamFlags.EventCallback, num, 0L, this.outputFormat, Guid.Empty); long streamLatency = this.audioClient.StreamLatency; if (streamLatency != 0L) { this.latencyMilliseconds = (int)(streamLatency / 10000L); } } else { this.audioClient.Initialize(this.shareMode, AudioClientStreamFlags.EventCallback, num, num, this.outputFormat, Guid.Empty); } this.frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); this.audioClient.SetEventHandle(this.frameEventWaitHandle.SafeWaitHandle.DangerousGetHandle()); } else { this.audioClient.Initialize(this.shareMode, AudioClientStreamFlags.None, num, 0L, this.outputFormat, Guid.Empty); } this.renderClient = this.audioClient.AudioRenderClient; }
/// <summary> /// Initialize for playing the specified wave stream /// </summary> /// <param name="waveProvider">IWaveProvider to play</param> public void Init(IWaveProvider waveProvider) { long latencyRefTimes = latencyMilliseconds * 10000; outputFormat = waveProvider.WaveFormat; // first attempt uses the WaveFormat from the WaveStream WaveFormatExtensible closestSampleRateFormat; if (!audioClient.IsFormatSupported(shareMode, outputFormat, out closestSampleRateFormat)) { // Use closesSampleRateFormat (in sharedMode, it equals usualy to the audioClient.MixFormat) // See documentation : http://msdn.microsoft.com/en-us/library/ms678737(VS.85).aspx // They say : "In shared mode, the audio engine always supports the mix format" // The MixFormat is more likely to be a WaveFormatExtensible. if (closestSampleRateFormat == null) { outputFormat = GetFallbackFormat(); } else { outputFormat = closestSampleRateFormat; } if (!windowsN) { try { // just check that we can make it. using (new ResamplerDmoStream(waveProvider, outputFormat)) { } } catch (Exception) { // On Windows 10 some poorly coded drivers return a bad format in to closestSampleRateFormat // In that case, try and fallback as if it provided no closest (e.g. force trying the mix format) outputFormat = GetFallbackFormat(); try { using (new ResamplerDmoStream(waveProvider, outputFormat)) { } } catch (Exception) { //still something wrong - assume windows N and DMO is broken in some way windowsN = true; } } } dmoResamplerNeeded = true; } else { dmoResamplerNeeded = false; } sourceProvider = waveProvider; // If using EventSync, setup is specific with shareMode if (isUsingEventSync) { // Init Shared or Exclusive if (shareMode == AudioClientShareMode.Shared) { // With EventCallBack and Shared, both latencies must be set to 0 (update - not sure this is true anymore) // audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, 0, outputFormat, Guid.Empty); // Windows 10 returns 0 from stream latency, resulting in maxing out CPU usage later var streamLatency = audioClient.StreamLatency; if (streamLatency != 0) { // Get back the effective latency from AudioClient latencyMilliseconds = (int)(streamLatency / 10000); } } else { // With EventCallBack and Exclusive, both latencies must equals audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, outputFormat, Guid.Empty); } // Create the Wait Event Handle frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); audioClient.SetEventHandle(frameEventWaitHandle.SafeWaitHandle.DangerousGetHandle()); } else { // Normal setup for both sharedMode audioClient.Initialize(shareMode, AudioClientStreamFlags.None, latencyRefTimes, 0, outputFormat, Guid.Empty); } // Get the RenderClient renderClient = audioClient.AudioRenderClient; }
/// <summary> /// Initialize for playing the specified wave stream /// </summary> /// <param name="waveProvider">IWaveProvider to play</param> public void Init(IWaveProvider waveProvider) { long latencyRefTimes = latencyMilliseconds * 10000; outputFormat = waveProvider.WaveFormat; // first attempt uses the WaveFormat from the WaveStream WaveFormatExtensible closestSampleRateFormat; if (!audioClient.IsFormatSupported(shareMode, outputFormat, out closestSampleRateFormat)) { // Use closesSampleRateFormat (in sharedMode, it equals usualy to the audioClient.MixFormat) // See documentation : http://msdn.microsoft.com/en-us/library/ms678737(VS.85).aspx // They say : "In shared mode, the audio engine always supports the mix format" // The MixFormat is more likely to be a WaveFormatExtensible. if (closestSampleRateFormat == null) { WaveFormat correctSampleRateFormat = audioClient.MixFormat; /*WaveFormat.CreateIeeeFloatWaveFormat( * audioClient.MixFormat.SampleRate, * audioClient.MixFormat.Channels);*/ if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { // Iterate from Worst to Best Format WaveFormatExtensible[] bestToWorstFormats = { new WaveFormatExtensible( outputFormat.SampleRate, 32, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 24, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 16, outputFormat.Channels), }; // Check from best Format to worst format ( Float32, Int24, Int16 ) for (int i = 0; i < bestToWorstFormats.Length; i++) { correctSampleRateFormat = bestToWorstFormats[i]; if (audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { break; } correctSampleRateFormat = null; } // If still null, then test on the PCM16, 2 channels if (correctSampleRateFormat == null) { // Last Last Last Chance (Thanks WASAPI) correctSampleRateFormat = new WaveFormatExtensible(outputFormat.SampleRate, 16, 2); if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { throw new NotSupportedException("Can't find a supported format to use"); } } } outputFormat = correctSampleRateFormat; } else { outputFormat = closestSampleRateFormat; } // just check that we can make it. using (new ResamplerDmoStream(waveProvider, outputFormat)) { } this.dmoResamplerNeeded = true; } else { dmoResamplerNeeded = false; } this.sourceProvider = waveProvider; // If using EventSync, setup is specific with shareMode if (isUsingEventSync) { // Init Shared or Exclusive if (shareMode == AudioClientShareMode.Shared) { // With EventCallBack and Shared, both latencies must be set to 0 audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, 0, 0, outputFormat, Guid.Empty); // Get back the effective latency from AudioClient latencyMilliseconds = (int)(audioClient.StreamLatency / 10000); } else { // With EventCallBack and Exclusive, both latencies must equals audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, outputFormat, Guid.Empty); } // Create the Wait Event Handle frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); audioClient.SetEventHandle(frameEventWaitHandle.SafeWaitHandle.DangerousGetHandle()); } else { // Normal setup for both sharedMode audioClient.Initialize(shareMode, AudioClientStreamFlags.None, latencyRefTimes, 0, outputFormat, Guid.Empty); } // Get the RenderClient renderClient = audioClient.AudioRenderClient; }
/// <summary> /// Initialize for playing the specified wave stream /// </summary> /// <param name="waveProvider">IWaveProvider to play</param> public void Init(IWaveProvider waveProvider) { long latencyRefTimes = latencyMilliseconds * 10000; outputFormat = waveProvider.WaveFormat; // first attempt uses the WaveFormat from the WaveStream WaveFormatExtensible closestSampleRateFormat; if (!audioClient.IsFormatSupported(shareMode, outputFormat, out closestSampleRateFormat)) { // Use closesSampleRateFormat (in sharedMode, it equals usualy to the audioClient.MixFormat) // See documentation : http://msdn.microsoft.com/en-us/library/ms678737(VS.85).aspx // They say : "In shared mode, the audio engine always supports the mix format" // The MixFormat is more likely to be a WaveFormatExtensible. if (closestSampleRateFormat == null) { WaveFormat correctSampleRateFormat = audioClient.MixFormat; /*WaveFormat.CreateIeeeFloatWaveFormat( * audioClient.MixFormat.SampleRate, * audioClient.MixFormat.Channels);*/ if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { // Iterate from Worst to Best Format WaveFormatExtensible[] bestToWorstFormats = { new WaveFormatExtensible( outputFormat.SampleRate, 32, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 24, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 16, outputFormat.Channels), }; // Check from best Format to worst format ( Float32, Int24, Int16 ) for (int i = 0; i < bestToWorstFormats.Length; i++) { correctSampleRateFormat = bestToWorstFormats[i]; if (audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { break; } correctSampleRateFormat = null; } // If still null, then test on the PCM16, 2 channels if (correctSampleRateFormat == null) { // Last Last Last Chance (Thanks WASAPI) correctSampleRateFormat = new WaveFormatExtensible(outputFormat.SampleRate, 16, 2); if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { throw new NotSupportedException("Can't find a supported format to use"); } } } outputFormat = correctSampleRateFormat; } else { outputFormat = closestSampleRateFormat; } // just check that we can make it. using (new ResamplerDmoStream(waveProvider, outputFormat)) { } dmoResamplerNeeded = true; } else { dmoResamplerNeeded = false; } sourceProvider = waveProvider; // If using EventSync, setup is specific with shareMode if (isUsingEventSync) { // Init Shared or Exclusive if (shareMode == AudioClientShareMode.Shared) { // With EventCallBack and Shared, both latencies must be set to 0 (update - not sure this is true anymore) // audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, 0, outputFormat, Guid.Empty); // Windows 10 returns 0 from stream latency, resulting in maxing out CPU usage later var streamLatency = audioClient.StreamLatency; if (streamLatency != 0) { // Get back the effective latency from AudioClient latencyMilliseconds = (int)(streamLatency / 10000); } } else { try { // With EventCallBack and Exclusive, both latencies must equals audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, outputFormat, Guid.Empty); } catch (COMException ex) { // Starting with Windows 7, Initialize can return AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED for a render device. // We should to initialize again. if (ex.ErrorCode != ErrorCodes.AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) { throw ex; } // Calculate the new latency. long newLatencyRefTimes = (long)(10000000.0 / (double)this.outputFormat.SampleRate * (double)this.audioClient.BufferSize + 0.5); this.audioClient.Dispose(); this.audioClient = this.mmDevice.AudioClient; this.audioClient.Initialize(this.shareMode, AudioClientStreamFlags.EventCallback, newLatencyRefTimes, newLatencyRefTimes, this.outputFormat, Guid.Empty); } } // Create the Wait Event Handle frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); audioClient.SetEventHandle(frameEventWaitHandle.SafeWaitHandle.DangerousGetHandle()); } else { // Normal setup for both sharedMode audioClient.Initialize(shareMode, AudioClientStreamFlags.None, latencyRefTimes, 0, outputFormat, Guid.Empty); } // Get the RenderClient renderClient = audioClient.AudioRenderClient; }
/// <summary> /// Initialize for playing the specified wave stream /// </summary> /// <param name="waveProvider">IWaveProvider to play</param> public void Init(IWaveProvider waveProvider) { long latencyRefTimes = latencyMilliseconds * 10000; outputFormat = waveProvider.WaveFormat; // first attempt uses the WaveFormat from the WaveStream WaveFormatExtensible closestSampleRateFormat; if (!audioClient.IsFormatSupported(shareMode, outputFormat, out closestSampleRateFormat)) { // Use closesSampleRateFormat (in sharedMode, it equals usualy to the audioClient.MixFormat) // See documentation : http://msdn.microsoft.com/en-us/library/ms678737(VS.85).aspx // They say : "In shared mode, the audio engine always supports the mix format" // The MixFormat is more likely to be a WaveFormatExtensible. if (closestSampleRateFormat == null) { WaveFormat correctSampleRateFormat = audioClient.MixFormat; if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { // Iterate from Worst to Best Format WaveFormatExtensible[] bestToWorstFormats = { new WaveFormatExtensible( outputFormat.SampleRate, 32, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 24, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 16, outputFormat.Channels), }; // Check from best Format to worst format ( Float32, Int24, Int16 ) for (int i = 0; i < bestToWorstFormats.Length; i++) { correctSampleRateFormat = bestToWorstFormats[i]; if (audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { break; } correctSampleRateFormat = null; } // If still null, then test on the PCM16, 2 channels if (correctSampleRateFormat == null) { // Last Last Last Chance (Thanks WASAPI) correctSampleRateFormat = new WaveFormatExtensible(outputFormat.SampleRate, 16, 2); if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { throw new NotSupportedException("Can't find a supported format to use"); } } } outputFormat = correctSampleRateFormat; } else { outputFormat = closestSampleRateFormat; } // just check that we can make it. resamplerDmoStream = new ResamplerDmoStream(waveProvider, outputFormat); sourceProvider = resamplerDmoStream; } else { sourceProvider = waveProvider; } // Normal setup for both sharedMode audioClient.Initialize(shareMode, AudioClientStreamFlags.None, latencyRefTimes, 0, outputFormat, Guid.Empty); // Get the RenderClient renderClient = audioClient.AudioRenderClient; // set up the read buffer bufferFrameCount = audioClient.BufferSize; bytesPerFrame = outputFormat.Channels * outputFormat.BitsPerSample / 8; readBuffer = new byte[bufferFrameCount * bytesPerFrame]; }
/// <summary> /// Dispose /// </summary> public void Dispose() { if (audioClientInterface != null) { if (audioClockClient != null) { audioClockClient.Dispose(); audioClockClient = null; } if (audioRenderClient != null) { audioRenderClient.Dispose(); audioRenderClient = null; } if (audioCaptureClient != null) { audioCaptureClient.Dispose(); audioCaptureClient = null; } Marshal.ReleaseComObject(audioClientInterface); audioClientInterface = null; GC.SuppressFinalize(this); } }
/// <summary> /// Initialize for playing the specified wave stream /// </summary> /// <param name="waveProvider">IWaveProvider to play</param> public void Init(IWaveProvider waveProvider) { long latencyRefTimes = latencyMilliseconds * 10000; outputFormat = waveProvider.WaveFormat; // first attempt uses the WaveFormat from the WaveStream WaveFormatExtensible closestSampleRateFormat; if (!audioClient.IsFormatSupported(shareMode, outputFormat, out closestSampleRateFormat)) { // Use closesSampleRateFormat (in sharedMode, it equals usualy to the audioClient.MixFormat) // See documentation : http://msdn.microsoft.com/en-us/library/ms678737(VS.85).aspx // They say : "In shared mode, the audio engine always supports the mix format" // The MixFormat is more likely to be a WaveFormatExtensible. if (closestSampleRateFormat == null) { outputFormat = GetFallbackFormat(); } else { outputFormat = closestSampleRateFormat; } try { // just check that we can make it. using (new ResamplerDmoStream(waveProvider, outputFormat)) { } } catch (Exception) { // On Windows 10 some poorly coded drivers return a bad format in to closestSampleRateFormat // In that case, try and fallback as if it provided no closest (e.g. force trying the mix format) outputFormat = GetFallbackFormat(); using (new ResamplerDmoStream(waveProvider, outputFormat)) { } } dmoResamplerNeeded = true; } else { dmoResamplerNeeded = false; } sourceProvider = waveProvider; // If using EventSync, setup is specific with shareMode if (isUsingEventSync) { // Init Shared or Exclusive if (shareMode == AudioClientShareMode.Shared) { // With EventCallBack and Shared, both latencies must be set to 0 (update - not sure this is true anymore) // audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, 0, outputFormat, Guid.Empty); // Windows 10 returns 0 from stream latency, resulting in maxing out CPU usage later var streamLatency = audioClient.StreamLatency; if (streamLatency != 0) { // Get back the effective latency from AudioClient latencyMilliseconds = (int)(streamLatency / 10000); } } else { try { // With EventCallBack and Exclusive, both latencies must equals audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, outputFormat, Guid.Empty); } catch (COMException ex) { // Starting with Windows 7, Initialize can return AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED for a render device. // We should to initialize again. if (ex.ErrorCode != ErrorCodes.AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) { throw ex; } // Calculate the new latency. long newLatencyRefTimes = (long)(10000000.0 / (double)this.outputFormat.SampleRate * (double)this.audioClient.BufferSize + 0.5); this.audioClient.Dispose(); this.audioClient = this.mmDevice.AudioClient; this.audioClient.Initialize(this.shareMode, AudioClientStreamFlags.EventCallback, newLatencyRefTimes, newLatencyRefTimes, this.outputFormat, Guid.Empty); } } // Create the Wait Event Handle frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); audioClient.SetEventHandle(frameEventWaitHandle.SafeWaitHandle.DangerousGetHandle()); } else { // Normal setup for both sharedMode audioClient.Initialize(shareMode, AudioClientStreamFlags.None, latencyRefTimes, 0, outputFormat, Guid.Empty); } // Get the RenderClient renderClient = audioClient.AudioRenderClient; }
/// <summary> /// Initialize for playing the specified wave stream /// </summary> /// <param name="waveProvider">IWaveProvider to play</param> public void Init(IWaveProvider waveProvider) { long latencyRefTimes = latencyMilliseconds * 10000; outputFormat = waveProvider.WaveFormat; // first attempt uses the WaveFormat from the WaveStream WaveFormatExtensible closestSampleRateFormat; if (!audioClient.IsFormatSupported(shareMode, outputFormat, out closestSampleRateFormat)) { // Use closesSampleRateFormat (in sharedMode, it equals usualy to the audioClient.MixFormat) // See documentation : http://msdn.microsoft.com/en-us/library/ms678737(VS.85).aspx // They say : "In shared mode, the audio engine always supports the mix format" // The MixFormat is more likely to be a WaveFormatExtensible. if (closestSampleRateFormat == null) { WaveFormat correctSampleRateFormat = audioClient.MixFormat; /*WaveFormat.CreateIeeeFloatWaveFormat( audioClient.MixFormat.SampleRate, audioClient.MixFormat.Channels);*/ if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { // Iterate from Worst to Best Format WaveFormatExtensible[] bestToWorstFormats = { new WaveFormatExtensible( outputFormat.SampleRate, 32, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 24, outputFormat.Channels), new WaveFormatExtensible( outputFormat.SampleRate, 16, outputFormat.Channels), }; // Check from best Format to worst format ( Float32, Int24, Int16 ) for (int i = 0; i < bestToWorstFormats.Length; i++ ) { correctSampleRateFormat = bestToWorstFormats[i]; if ( audioClient.IsFormatSupported(shareMode, correctSampleRateFormat) ) { break; } correctSampleRateFormat = null; } // If still null, then test on the PCM16, 2 channels if (correctSampleRateFormat == null) { // Last Last Last Chance (Thanks WASAPI) correctSampleRateFormat = new WaveFormatExtensible(outputFormat.SampleRate, 16, 2); if (!audioClient.IsFormatSupported(shareMode, correctSampleRateFormat)) { throw new NotSupportedException("Can't find a supported format to use"); } } } outputFormat = correctSampleRateFormat; } else { outputFormat = closestSampleRateFormat; } // just check that we can make it. using (new ResamplerDmoStream(waveProvider, outputFormat)) { } this.dmoResamplerNeeded = true; } else { dmoResamplerNeeded = false; } this.sourceProvider = waveProvider; // If using EventSync, setup is specific with shareMode if (isUsingEventSync) { // Init Shared or Exclusive if (shareMode == AudioClientShareMode.Shared) { // With EventCallBack and Shared, both latencies must be set to 0 audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, 0, 0, outputFormat, Guid.Empty); // Get back the effective latency from AudioClient latencyMilliseconds = (int)(audioClient.StreamLatency / 10000); } else { // With EventCallBack and Exclusive, both latencies must equals audioClient.Initialize(shareMode, AudioClientStreamFlags.EventCallback, latencyRefTimes, latencyRefTimes, outputFormat, Guid.Empty); } // Create the Wait Event Handle frameEventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset); audioClient.SetEventHandle(frameEventWaitHandle.SafeWaitHandle.DangerousGetHandle()); } else { // Normal setup for both sharedMode audioClient.Initialize(shareMode, AudioClientStreamFlags.None, latencyRefTimes, 0, outputFormat, Guid.Empty); } // Get the RenderClient renderClient = audioClient.AudioRenderClient; }