SDRSharp/SDRSharp.Radio/SDRSharp.Radio.PortAudio/WaveRecorder.cs
2018-03-24 23:01:41 -07:00

83 lines
2.4 KiB
C#

using PortAudioSharp;
using System;
using System.Runtime.InteropServices;
namespace SDRSharp.Radio.PortAudio
{
public class WaveRecorder : IDisposable
{
private IntPtr _streamHandle;
private GCHandle _gcHandle;
private readonly AudioBufferAvailableDelegate _bufferAvailable;
private unsafe readonly PaStreamCallbackDelegate _paCallback = WaveRecorder.PaStreamCallback;
public unsafe WaveRecorder(int deviceIndex, double sampleRate, int framesPerBuffer, AudioBufferAvailableDelegate bufferAvailable)
{
this._bufferAvailable = bufferAvailable;
PaStreamParameters paStreamParameters = new PaStreamParameters
{
device = deviceIndex,
channelCount = 2,
suggestedLatency = 0.0,
sampleFormat = PaSampleFormat.PaFloat32
};
PaError paError = PortAudioAPI.Pa_IsFormatSupported(ref paStreamParameters, IntPtr.Zero, sampleRate);
if (paError != 0)
{
throw new ApplicationException(paError.ToString());
}
this._gcHandle = GCHandle.Alloc(this);
paError = PortAudioAPI.Pa_OpenStream(out this._streamHandle, ref paStreamParameters, IntPtr.Zero, sampleRate, (uint)framesPerBuffer, PaStreamFlags.PaNoFlag, this._paCallback, (IntPtr)this._gcHandle);
if (paError != 0)
{
this._gcHandle.Free();
throw new ApplicationException(paError.ToString());
}
paError = PortAudioAPI.Pa_StartStream(this._streamHandle);
if (paError == PaError.paNoError)
{
return;
}
PortAudioAPI.Pa_CloseStream(this._streamHandle);
this._gcHandle.Free();
throw new ApplicationException(paError.ToString());
}
private unsafe static PaStreamCallbackResult PaStreamCallback(float* input, float* output, uint frameCount, ref PaStreamCallbackTimeInfo timeInfo, PaStreamCallbackFlags statusFlags, IntPtr userData)
{
GCHandle gCHandle = GCHandle.FromIntPtr(userData);
if (!gCHandle.IsAllocated)
{
return PaStreamCallbackResult.PaAbort;
}
WaveRecorder waveRecorder = (WaveRecorder)gCHandle.Target;
try
{
if (waveRecorder._bufferAvailable != null)
{
waveRecorder._bufferAvailable(input, (int)frameCount);
}
}
catch
{
return PaStreamCallbackResult.PaAbort;
}
return PaStreamCallbackResult.PaContinue;
}
public void Dispose()
{
if (this._streamHandle != IntPtr.Zero)
{
PortAudioAPI.Pa_StopStream(this._streamHandle);
PortAudioAPI.Pa_CloseStream(this._streamHandle);
this._streamHandle = IntPtr.Zero;
}
this._gcHandle.Free();
}
}
}