SDRSharp/SDRSharp.Radio/SDRSharp.Radio.PortAudio/WavePlayer.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 WavePlayer : IDisposable
{
private IntPtr _streamHandle;
private GCHandle _gcHandle;
private readonly AudioBufferNeededDelegate _bufferNeeded;
private unsafe readonly PaStreamCallbackDelegate _paCallback = WavePlayer.PaStreamCallback;
public unsafe WavePlayer(int deviceIndex, double sampleRate, int framesPerBuffer, AudioBufferNeededDelegate bufferNeededDelegate)
{
this._bufferNeeded = bufferNeededDelegate;
PaStreamParameters paStreamParameters = new PaStreamParameters
{
device = deviceIndex,
channelCount = 2,
suggestedLatency = 0.0,
sampleFormat = PaSampleFormat.PaFloat32
};
PaError paError = PortAudioAPI.Pa_IsFormatSupported(IntPtr.Zero, ref paStreamParameters, sampleRate);
if (paError != 0)
{
throw new ApplicationException(paError.ToString());
}
this._gcHandle = GCHandle.Alloc(this);
paError = PortAudioAPI.Pa_OpenStream(out this._streamHandle, IntPtr.Zero, ref paStreamParameters, 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;
}
WavePlayer wavePlayer = (WavePlayer)gCHandle.Target;
try
{
if (wavePlayer._bufferNeeded != null)
{
wavePlayer._bufferNeeded(output, (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();
}
}
}