23#include <freerdp/config.h>
27#include <winpr/cmdline.h>
29#include <freerdp/freerdp.h>
30#include <freerdp/channels/rdpsnd.h>
32#include "audin_main.h"
42 UINT32 FramesPerPacket;
47 rdpContext* rdpcontext;
50static BOOL audin_sndio_format_supported(IAudinDevice* device,
const AUDIO_FORMAT* format)
52 if (device ==
nullptr || format ==
nullptr)
55 return (format->wFormatTag == WAVE_FORMAT_PCM);
63static UINT audin_sndio_set_format(IAudinDevice* device,
AUDIO_FORMAT* format,
64 UINT32 FramesPerPacket)
66 AudinSndioDevice* sndio = (AudinSndioDevice*)device;
68 if (device ==
nullptr || format ==
nullptr)
69 return ERROR_INVALID_PARAMETER;
71 if (format->wFormatTag != WAVE_FORMAT_PCM)
72 return ERROR_INTERNAL_ERROR;
74 sndio->format = *format;
75 sndio->FramesPerPacket = FramesPerPacket;
80static void* audin_sndio_thread_func(
void* arg)
84 BYTE* buffer =
nullptr;
86 AudinSndioDevice* sndio = (AudinSndioDevice*)arg;
92 error = ERROR_INVALID_PARAMETER;
96 hdl = sio_open(SIO_DEVANY, SIO_REC, 0);
99 WLog_ERR(TAG,
"could not open audio device");
100 error = ERROR_INTERNAL_ERROR;
105 par.bits = sndio->format.wBitsPerSample;
106 par.rchan = sndio->format.nChannels;
107 par.rate = sndio->format.nSamplesPerSec;
108 if (!sio_setpar(hdl, &par))
110 WLog_ERR(TAG,
"could not set audio parameters");
111 error = ERROR_INTERNAL_ERROR;
114 if (!sio_getpar(hdl, &par))
116 WLog_ERR(TAG,
"could not get audio parameters");
117 error = ERROR_INTERNAL_ERROR;
123 WLog_ERR(TAG,
"could not start audio device");
124 error = ERROR_INTERNAL_ERROR;
128 const size_t nbytes = (1ull * sndio->FramesPerPacket * sndio->format.nChannels *
129 (sndio->format.wBitsPerSample / 8));
130 if (nbytes > INT32_MAX)
133 buffer = (BYTE*)calloc((nbytes +
sizeof(
void*)),
sizeof(BYTE));
135 if (buffer ==
nullptr)
137 error = ERROR_NOT_ENOUGH_MEMORY;
143 status = WaitForSingleObject(sndio->stopEvent, 0);
145 if (status == WAIT_FAILED)
147 error = GetLastError();
148 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
152 if (status == WAIT_OBJECT_0)
155 n = sio_read(hdl, buffer, nbytes);
159 WLog_ERR(TAG,
"could not read");
166 if ((error = sndio->receive(&sndio->format, buffer, nbytes, sndio->user_data)))
168 WLog_ERR(TAG,
"sndio->receive failed with error %" PRIu32
"", error);
174 if (error && sndio && sndio->rdpcontext)
175 setChannelError(sndio->rdpcontext, error,
"audin_sndio_thread_func reported an error");
179 WLog_INFO(TAG,
"sio_close");
194static UINT audin_sndio_open(IAudinDevice* device, AudinReceive receive,
void* user_data)
196 AudinSndioDevice* sndio = (AudinSndioDevice*)device;
197 sndio->receive = receive;
198 sndio->user_data = user_data;
200 if (!(sndio->stopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
202 WLog_ERR(TAG,
"CreateEvent failed");
203 return ERROR_INTERNAL_ERROR;
206 if (!(sndio->thread = CreateThread(
nullptr, 0, (LPTHREAD_START_ROUTINE)audin_sndio_thread_func,
209 WLog_ERR(TAG,
"CreateThread failed");
210 (void)CloseHandle(sndio->stopEvent);
211 sndio->stopEvent =
nullptr;
212 return ERROR_INTERNAL_ERROR;
215 return CHANNEL_RC_OK;
223static UINT audin_sndio_close(IAudinDevice* device)
226 AudinSndioDevice* sndio = (AudinSndioDevice*)device;
228 if (device ==
nullptr)
229 return ERROR_INVALID_PARAMETER;
231 if (sndio->stopEvent !=
nullptr)
233 (void)SetEvent(sndio->stopEvent);
235 if (WaitForSingleObject(sndio->thread, INFINITE) == WAIT_FAILED)
237 error = GetLastError();
238 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"", error);
242 (void)CloseHandle(sndio->stopEvent);
243 sndio->stopEvent =
nullptr;
244 (void)CloseHandle(sndio->thread);
245 sndio->thread =
nullptr;
248 sndio->receive =
nullptr;
249 sndio->user_data =
nullptr;
251 return CHANNEL_RC_OK;
259static UINT audin_sndio_free(IAudinDevice* device)
261 AudinSndioDevice* sndio = (AudinSndioDevice*)device;
264 if (device ==
nullptr)
265 return ERROR_INVALID_PARAMETER;
267 if ((error = audin_sndio_close(device)))
269 WLog_ERR(TAG,
"audin_sndio_close failed with error code %d", error);
274 return CHANNEL_RC_OK;
282static UINT audin_sndio_parse_addin_args(AudinSndioDevice* device,
ADDIN_ARGV* args)
287 AudinSndioDevice* sndio = (AudinSndioDevice*)device;
289 nullptr,
nullptr } };
291 COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
292 status = CommandLineParseArgumentsA(args->argc, (
const char**)args->argv, audin_sndio_args,
293 flags, sndio,
nullptr,
nullptr);
296 return ERROR_INVALID_PARAMETER;
298 arg = audin_sndio_args;
302 if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
305 CommandLineSwitchStart(arg) CommandLineSwitchEnd(arg)
306 }
while ((arg = CommandLineFindNextArgumentA(arg)) !=
nullptr);
308 return CHANNEL_RC_OK;
316FREERDP_ENTRY_POINT(UINT VCAPITYPE sndio_freerdp_audin_client_subsystem_entry(
320 AudinSndioDevice* sndio;
321 UINT ret = CHANNEL_RC_OK;
322 sndio = (AudinSndioDevice*)calloc(1,
sizeof(AudinSndioDevice));
324 if (sndio ==
nullptr)
325 return CHANNEL_RC_NO_MEMORY;
327 sndio->device.Open = audin_sndio_open;
328 sndio->device.FormatSupported = audin_sndio_format_supported;
329 sndio->device.SetFormat = audin_sndio_set_format;
330 sndio->device.Close = audin_sndio_close;
331 sndio->device.Free = audin_sndio_free;
332 sndio->rdpcontext = pEntryPoints->rdpcontext;
333 args = pEntryPoints->args;
337 ret = audin_sndio_parse_addin_args(sndio, args);
339 if (ret != CHANNEL_RC_OK)
341 WLog_ERR(TAG,
"error parsing arguments");
346 if ((ret = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)sndio)))
348 WLog_ERR(TAG,
"RegisterAudinDevice failed with error %" PRIu32
"", ret);
354 audin_sndio_free(&sndio->device);