mirror of
https://github.com/SDRSharpR/SDRSharp.git
synced 2025-12-06 03:42:01 +01:00
83 lines
2.4 KiB
C#
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();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|