/// <summary> /// Initializes a new instance of the <see cref="Pipe"/> class. /// </summary> /// <param name="input">Audio device from which to capture audio.</param> /// <param name="outputs">Audio devices to which the captured audio should be output.</param> /// <param name="latency">Latency of the pipe in milliseconds. </param> public MultiOutputAudioPipe(MMDevice input, MultiChannelList <MMDevice> outputs, int latency = DefaultLatency) { foreach (var output in outputs) { if (DeviceService.Equals(input, output)) { throw new ArgumentException($"{nameof(input)} and {nameof(output)} cannot both be {input.FriendlyName}"); } } if (latency < MinLatency) { throw new ArgumentException("Latency is too low.", nameof(latency)); } InputDevice = input; OutputDevices = outputs; try { inputCapture = new WasapiLoopbackCapture(InputDevice); } catch (COMException ex) { throw new PipeInitException(ex.HResult, InputDevice); } waveBuffers = new MultiChannelList <BufferedWaveProvider>(OutputDevices.Select(device => new BufferedWaveProvider(inputCapture.WaveFormat)).ToList()); waveMultiplexers = new MultiChannelList <MultiplexingWaveProvider>(waveBuffers.Select(waveBuffer => new MultiplexingWaveProvider(new BufferedWaveProvider[] { waveBuffer }, 1))); waveMultiplexers.RightDevice.ConnectInputToOutput(0, 0); waveMultiplexers.LeftDevice.ConnectInputToOutput(1, 0); inputCapture.DataAvailable += (sender, e) => { waveBuffers.AsParallel().ForAll(buffer => buffer.AddSamples(e.Buffer, 0, e.BytesRecorded)); }; try { outputDevices = new MultiChannelList <WasapiOut>(OutputDevices.AsParallel().Select(device => new WasapiOut(device, AudioClientShareMode.Shared, true, latency)).ToList()); outputDevices.Zip(waveMultiplexers, (device, multiplexer) => new { Device = device, Multiplexer = multiplexer }).AsParallel().ForAll(z => z.Device.Init(z.Multiplexer)); } catch (COMException ex) { throw new PipeInitException(ex.HResult, null); } }
/// <summary> /// Initializes a new instance of the <see cref="Pipe"/> class. /// </summary> /// <param name="input">Audio device from which to capture audio.</param> /// <param name="output">Audio device to which the captured audio should be output.</param> /// <param name="latency">Latency of the pipe in milliseconds. </param> public Pipe(MMDevice input, MMDevice output, int latency = DefaultLatency) { if (DeviceService.Equals(input, output)) { throw new ArgumentException($"{nameof(input)} and {nameof(output)} cannot both be {input.FriendlyName}"); } if (latency < MinLatency) { throw new ArgumentException("Latency is too low.", nameof(latency)); } InputDevice = input; OutputDevice = output; try { inputCapture = new WasapiLoopbackCapture(InputDevice); } catch (COMException ex) { throw new PipeInitException(ex.HResult, InputDevice); } buffer = new BufferedWaveProvider(inputCapture.WaveFormat); inputCapture.DataAvailable += (sender, e) => { buffer.AddSamples(e.Buffer, 0, e.BytesRecorded); }; try { outputDevice = new WasapiOut(OutputDevice, AudioClientShareMode.Shared, true, latency); outputDevice.Init(buffer); } catch (COMException ex) { throw new PipeInitException(ex.HResult, OutputDevice); } }