/// <summary> /// Create a PortAudioDevicePump for an input device /// Note: This MUST be disposed, or you risk breaking audio on the host until the next reboot /// </summary> /// <param name="device">The input device to create a pump for</param> /// <param name="channelCount">The number of channels to capture from the input device</param> /// <param name="sampleFormat">The sample format of the output PCM data</param> /// <param name="suggestedLatency">The latency the device will attempt to achieve</param> /// <param name="sampleRate">The sample rate of the output PCM data</param> /// <param name="callback">The callback that will be invoked when data is produced</param> /// <exception cref="ArgumentNullException">Thrown in the case that the device or callback are null</exception> public unsafe PortAudioDevicePump(PortAudioDevice device, int channelCount, PortAudioSampleFormat sampleFormat, TimeSpan suggestedLatency, double sampleRate, WriteDataCallback callback) { if (device == null) { throw new ArgumentNullException(nameof(device)); } if (callback == null) { throw new ArgumentNullException(nameof(callback)); } PortAudioLifetimeRegistry.Register(this); SampleFormat = sampleFormat; Channels = channelCount; SampleRate = sampleRate; SuggestedLatency = suggestedLatency; _handle = GCHandle.Alloc(this); _isOutput = false; _writeDataCallback = callback; var inputParams = new PaStreamParameters { ChannelCount = channelCount, DeviceIndex = device.DeviceIndex, HostApiSpecificStreamInfo = IntPtr.Zero, SampleFormats = sampleFormat.SampleFormat, SuggestedLatency = new PaTime(suggestedLatency) }; var err = Native.PortAudio.Pa_OpenStream(out _stream, &inputParams, null, sampleRate, FRAMES_TO_BUFFER, PaStreamFlags.NoFlag, StreamCallback, GCHandle.ToIntPtr(_handle)); if (err < PaErrorCode.NoError) { throw PortAudioException.GetException(err); } err = Native.PortAudio.Pa_SetStreamFinishedCallback(_stream, StreamFinishedCallback); if (err < PaErrorCode.NoError) { throw PortAudioException.GetException(err); } }
private PortAudioContext() { PortAudioLifetimeRegistry.Register(this); }
/// <summary> /// Create a PortAudioDevicePump for an output device /// Note: This MUST be disposed, or you risk breaking audio on the host until the next reboot /// </summary> /// <param name="device">The output device to create a pump for</param> /// <param name="channelCount">The number of channels in the input PCM data</param> /// <param name="sampleFormat">The sample format of the input PCM data</param> /// <param name="suggestedLatency">The latency the device will attempt to achieve</param> /// <param name="sampleRate">The sample rate of playback</param> /// <param name="callback">The callback that will supply data to the output device</param> /// <exception cref="ArgumentNullException">Thrown in the case that the device or callback are null</exception> public unsafe PortAudioDevicePump(PortAudioDevice device, int channelCount, PortAudioSampleFormat sampleFormat, TimeSpan suggestedLatency, double sampleRate, ReadDataCallback callback) { if (device == null) { throw new ArgumentNullException(nameof(device)); } if (callback == null) { throw new ArgumentNullException(nameof(callback)); } PortAudioLifetimeRegistry.Register(this); SampleFormat = sampleFormat; Channels = channelCount; SampleRate = sampleRate; SuggestedLatency = suggestedLatency; _handle = GCHandle.Alloc(this); _isOutput = true; _readDataCallback = callback; var outputParams = new PaStreamParameters { ChannelCount = channelCount, DeviceIndex = device.DeviceIndex, HostApiSpecificStreamInfo = IntPtr.Zero, SampleFormats = sampleFormat.SampleFormat, SuggestedLatency = new PaTime(suggestedLatency) }; var err = Native.PortAudio.Pa_OpenStream(out _stream, null, &outputParams, sampleRate, FRAMES_TO_BUFFER, PaStreamFlags.NoFlag, StreamCallback, GCHandle.ToIntPtr(_handle)); if (err < PaErrorCode.NoError) { throw PortAudioException.GetException(err); } err = Native.PortAudio.Pa_SetStreamFinishedCallback(_stream, StreamFinishedCallback); if (err < PaErrorCode.NoError) { throw PortAudioException.GetException(err); } _dataQueue = new ConcurrentQueue <BufferContainer>(); _bufferPool = new ConcurrentBag <BufferContainer>(); for (var i = 0; i < BUFFER_CHAIN_LENGTH; i++) { var buffer = new byte[FRAMES_TO_BUFFER * (ulong)channelCount * (ulong)sampleFormat.FormatSize]; var readLength = WriteAudioFrame(buffer, buffer.Length); _dataQueue.Enqueue(new BufferContainer(buffer) { ReadLength = readLength }); } _queueCount = new SemaphoreSlim(BUFFER_CHAIN_LENGTH); _poolCount = new SemaphoreSlim(0); _threadEndEvent = new ManualResetEventSlim(false); _processingThreadCancel = new CancellationTokenSource(); Task.Run(() => DataTask(_processingThreadCancel.Token)); }
internal PortAudioHostApi(PaHostApiIndex index) { PortAudioLifetimeRegistry.Register(this); _apiIndex = index; }
internal PortAudioDevice(PaDeviceIndex deviceIndex) { PortAudioLifetimeRegistry.Register(this); DeviceIndex = deviceIndex; }