From b3a2042103a192d9e4482691ce9e7d73f9475b09 Mon Sep 17 00:00:00 2001 From: Denis Date: Sun, 7 Mar 2021 12:51:36 +0100 Subject: [PATCH] Add support for OpenBSD sndio --- CMakeLists.txt | 10 +- channels/audin/client/CMakeLists.txt | 4 + channels/audin/client/audin_main.c | 3 + channels/audin/client/sndio/CMakeLists.txt | 34 ++ channels/audin/client/sndio/audin_sndio.c | 356 ++++++++++++++++++++ channels/rdpsnd/client/CMakeLists.txt | 4 + channels/rdpsnd/client/rdpsnd_main.c | 3 + channels/rdpsnd/client/sndio/CMakeLists.txt | 37 ++ channels/rdpsnd/client/sndio/rdpsnd_sndio.c | 220 ++++++++++++ client/common/CMakeLists.txt | 2 +- 10 files changed, 671 insertions(+), 2 deletions(-) create mode 100644 channels/audin/client/sndio/CMakeLists.txt create mode 100644 channels/audin/client/sndio/audin_sndio.c create mode 100644 channels/rdpsnd/client/sndio/CMakeLists.txt create mode 100644 channels/rdpsnd/client/sndio/rdpsnd_sndio.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bf9bb05d8..5c4189da91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -582,7 +582,8 @@ if(OPENBSD) set(WITH_MANPAGES "ON") set(WITH_ALSA "OFF") set(WITH_PULSE "OFF") - set(WITH_OSS "ON") + set(WITH_OSS "OFF") + set(WITH_SNDIO "ON") set(WITH_WAYLAND "OFF") endif() @@ -693,6 +694,10 @@ set(ALSA_FEATURE_TYPE "RECOMMENDED") set(ALSA_FEATURE_PURPOSE "sound") set(ALSA_FEATURE_DESCRIPTION "audio input, audio output and multimedia redirection") +set(SNDIO_FEATURE_TYPE "OPTIONAL") +set(SNDIO_FEATURE_PURPOSE "sound") +set(SNDIO_FEATURE_DESCRIPTION "OpenBSD audio input/output") + set(PULSE_FEATURE_TYPE "RECOMMENDED") set(PULSE_FEATURE_PURPOSE "sound") set(PULSE_FEATURE_DESCRIPTION "audio input, audio output and multimedia redirection") @@ -763,6 +768,7 @@ if(WIN32) set(ZLIB_FEATURE_TYPE "DISABLED") set(OSS_FEATURE_TYPE "DISABLED") set(ALSA_FEATURE_TYPE "DISABLED") + set(SNDIO_FEATURE_TYPE "DISABLED") set(PULSE_FEATURE_TYPE "DISABLED") set(CUPS_FEATURE_TYPE "DISABLED") set(PCSC_FEATURE_TYPE "DISABLED") @@ -778,6 +784,7 @@ if(APPLE) set(WAYLAND_FEATURE_TYPE "DISABLED") set(OSS_FEATURE_TYPE "DISABLED") set(ALSA_FEATURE_TYPE "DISABLED") + set(SNDIO_FEATURE_TYPE "DISABLED") if(IOS) set(X11_FEATURE_TYPE "DISABLED") set(PULSE_FEATURE_TYPE "DISABLED") @@ -807,6 +814,7 @@ if(ANDROID) set(WAYLAND_FEATURE_TYPE "DISABLED") set(OSS_FEATURE_TYPE "DISABLED") set(ALSA_FEATURE_TYPE "DISABLED") + set(SNDIO_FEATURE_TYPE "DISABLED") set(PULSE_FEATURE_TYPE "DISABLED") set(CUPS_FEATURE_TYPE "DISABLED") set(PCSC_FEATURE_TYPE "DISABLED") diff --git a/channels/audin/client/CMakeLists.txt b/channels/audin/client/CMakeLists.txt index 0c2e393eef..f03d99f1b7 100644 --- a/channels/audin/client/CMakeLists.txt +++ b/channels/audin/client/CMakeLists.txt @@ -56,3 +56,7 @@ endif() if(WITH_MACAUDIO) add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "mac" "") endif() + +if(WITH_SNDIO) + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "sndio" "") +endif() diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index 3044b3a3d7..ab7ecb652a 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -994,6 +994,9 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) #endif #if defined(WITH_MACAUDIO) { "mac", "default" }, +#endif +#if defined(WITH_SNDIO) + { "sndio", "default" }, #endif { NULL, NULL } }; diff --git a/channels/audin/client/sndio/CMakeLists.txt b/channels/audin/client/sndio/CMakeLists.txt new file mode 100644 index 0000000000..f6d846a20c --- /dev/null +++ b/channels/audin/client/sndio/CMakeLists.txt @@ -0,0 +1,34 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright (c) 2015 Rozhuk Ivan +# Copyright (c) 2020 Ingo Feinerer +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_client_subsystem("audin" "sndio" "") + +set(${MODULE_PREFIX}_SRCS + audin_sndio.c) + +include_directories(..) +include_directories(${SNDIO_INCLUDE_DIRS}) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + + + +set(${MODULE_PREFIX}_LIBS freerdp winpr ${SNDIO_LIBRARIES}) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + diff --git a/channels/audin/client/sndio/audin_sndio.c b/channels/audin/client/sndio/audin_sndio.c new file mode 100644 index 0000000000..1847ae0a5b --- /dev/null +++ b/channels/audin/client/sndio/audin_sndio.c @@ -0,0 +1,356 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel - sndio implementation + * + * Copyright (c) 2015 Rozhuk Ivan + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2020 Ingo Feinerer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include + +#include + +#include "audin_main.h" + +typedef struct _AudinSndioDevice +{ + IAudinDevice device; + + HANDLE thread; + HANDLE stopEvent; + + AUDIO_FORMAT format; + UINT32 FramesPerPacket; + + AudinReceive receive; + void* user_data; + + rdpContext* rdpcontext; +} AudinSndioDevice; + +static BOOL audin_sndio_format_supported(IAudinDevice* device, + const AUDIO_FORMAT* format) +{ + if (device == NULL || format == NULL) + return FALSE; + + return (format->wFormatTag == WAVE_FORMAT_PCM); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_sndio_set_format(IAudinDevice* device, AUDIO_FORMAT* format, + UINT32 FramesPerPacket) +{ + AudinSndioDevice* sndio = (AudinSndioDevice*)device; + + if (device == NULL || format == NULL) + return ERROR_INVALID_PARAMETER; + + if (format->wFormatTag != WAVE_FORMAT_PCM) + return ERROR_INTERNAL_ERROR; + + sndio->format = *format; + sndio->FramesPerPacket = FramesPerPacket; + + return CHANNEL_RC_OK; +} + +static void* audin_sndio_thread_func(void* arg) +{ + struct sio_hdl *hdl; + struct sio_par par; + BYTE* buffer = NULL; + size_t n, nbytes; + AudinSndioDevice* sndio = (AudinSndioDevice*)arg; + UINT error = 0; + DWORD status; + + if (arg == NULL) + { + error = ERROR_INVALID_PARAMETER; + goto err_out; + } + + hdl = sio_open(SIO_DEVANY, SIO_REC, 0); + if (hdl == NULL) { + WLog_ERR(TAG, "could not open audio device"); + error = ERROR_INTERNAL_ERROR; + goto err_out; + } + + sio_initpar(&par); + par.bits = sndio->format.wBitsPerSample; + par.rchan = sndio->format.nChannels; + par.rate = sndio->format.nSamplesPerSec; + if (!sio_setpar(hdl, &par)) { + WLog_ERR(TAG, "could not set audio parameters"); + error = ERROR_INTERNAL_ERROR; + goto err_out; + } + if (!sio_getpar(hdl, &par)) { + WLog_ERR(TAG, "could not get audio parameters"); + error = ERROR_INTERNAL_ERROR; + goto err_out; + } + + if (!sio_start(hdl)) { + WLog_ERR(TAG, "could not start audio device"); + error = ERROR_INTERNAL_ERROR; + goto err_out; + } + + nbytes = (sndio->FramesPerPacket * sndio->format.nChannels * + (sndio->format.wBitsPerSample / 8)); + buffer = (BYTE*)calloc((nbytes + sizeof(void*)), sizeof(BYTE)); + + if (buffer == NULL) + { + error = ERROR_NOT_ENOUGH_MEMORY; + goto err_out; + } + + while (1) + { + status = WaitForSingleObject(sndio->stopEvent, 0); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + goto err_out; + } + + if (status == WAIT_OBJECT_0) + break; + + n = sio_read(hdl, buffer, nbytes); + + if (n == 0) + { + WLog_ERR(TAG, "could not read"); + continue; + } + + if (n < nbytes) + continue; + + if ((error = sndio->receive(&sndio->format, buffer, nbytes, sndio->user_data))) + { + WLog_ERR(TAG, "sndio->receive failed with error %"PRIu32"", error); + break; + } + } + +err_out: + if (error && sndio->rdpcontext) + setChannelError(sndio->rdpcontext, error, + "audin_sndio_thread_func reported an error"); + + if (hdl != NULL) + { + WLog_INFO(TAG, "sio_close"); + sio_stop(hdl); + sio_close(hdl); + } + + free(buffer); + ExitThread(0); + return NULL; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_sndio_open(IAudinDevice* device, AudinReceive receive, + void* user_data) +{ + AudinSndioDevice* sndio = (AudinSndioDevice*)device; + sndio->receive = receive; + sndio->user_data = user_data; + + if (!(sndio->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed"); + return ERROR_INTERNAL_ERROR; + } + + if (!(sndio->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)audin_sndio_thread_func, sndio, 0, NULL))) + { + WLog_ERR(TAG, "CreateThread failed"); + CloseHandle(sndio->stopEvent); + sndio->stopEvent = NULL; + return ERROR_INTERNAL_ERROR; + } + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_sndio_close(IAudinDevice* device) +{ + UINT error; + AudinSndioDevice* sndio = (AudinSndioDevice*)device; + + if (device == NULL) + return ERROR_INVALID_PARAMETER; + + if (sndio->stopEvent != NULL) + { + SetEvent(sndio->stopEvent); + + if (WaitForSingleObject(sndio->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + return error; + } + + CloseHandle(sndio->stopEvent); + sndio->stopEvent = NULL; + CloseHandle(sndio->thread); + sndio->thread = NULL; + } + + sndio->receive = NULL; + sndio->user_data = NULL; + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_sndio_free(IAudinDevice* device) +{ + AudinSndioDevice* sndio = (AudinSndioDevice*)device; + int error; + + if (device == NULL) + return ERROR_INVALID_PARAMETER; + + if ((error = audin_sndio_close(device))) + { + WLog_ERR(TAG, "audin_sndio_close failed with error code %d", error); + } + + free(sndio); + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_sndio_parse_addin_args(AudinSndioDevice* device, ADDIN_ARGV* args) +{ + int status; + DWORD flags; + COMMAND_LINE_ARGUMENT_A* arg; + AudinSndioDevice* sndio = (AudinSndioDevice*)device; + COMMAND_LINE_ARGUMENT_A audin_sndio_args[] = { { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, + audin_sndio_args, flags, sndio, NULL, NULL); + + if (status < 0) + return ERROR_INVALID_PARAMETER; + + arg = audin_sndio_args; + + do + { + if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + continue; + + CommandLineSwitchStart(arg) CommandLineSwitchEnd(arg) + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + return CHANNEL_RC_OK; +} + +#ifdef BUILTIN_CHANNELS +#define freerdp_audin_client_subsystem_entry sndio_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) +{ + ADDIN_ARGV* args; + AudinSndioDevice* sndio; + UINT ret = CHANNEL_RC_OK; + sndio = (AudinSndioDevice*)calloc(1, sizeof(AudinSndioDevice)); + + if (sndio == NULL) + return CHANNEL_RC_NO_MEMORY; + + sndio->device.Open = audin_sndio_open; + sndio->device.FormatSupported = audin_sndio_format_supported; + sndio->device.SetFormat = audin_sndio_set_format; + sndio->device.Close = audin_sndio_close; + sndio->device.Free = audin_sndio_free; + sndio->rdpcontext = pEntryPoints->rdpcontext; + args = pEntryPoints->args; + + if (args->argc > 1) + { + ret = audin_sndio_parse_addin_args(sndio, args); + + if (ret != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "error parsing arguments"); + goto error; + } + } + + if ((ret = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, + (IAudinDevice*) sndio))) + { + WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"", ret); + goto error; + } + + return ret; +error: + audin_sndio_free(&sndio->device); + return ret; +} diff --git a/channels/rdpsnd/client/CMakeLists.txt b/channels/rdpsnd/client/CMakeLists.txt index 70f4aa2e6c..fa1813e41f 100644 --- a/channels/rdpsnd/client/CMakeLists.txt +++ b/channels/rdpsnd/client/CMakeLists.txt @@ -57,6 +57,10 @@ if(WITH_OPENSLES) add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "opensles" "") endif() +if(WITH_SNDIO) + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "sndio" "") +endif() + if (WITH_SERVER) add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "proxy" "") endif() diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index b6a82011f2..aef8fef1f5 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -988,6 +988,9 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) #endif #if defined(WITH_WINMM) { "winmm", "" }, +#endif +#if defined(WITH_SNDIO) + { "sndio", "" }, #endif { "fake", "" } }; diff --git a/channels/rdpsnd/client/sndio/CMakeLists.txt b/channels/rdpsnd/client/sndio/CMakeLists.txt new file mode 100644 index 0000000000..4b3ec8a911 --- /dev/null +++ b/channels/rdpsnd/client/sndio/CMakeLists.txt @@ -0,0 +1,37 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright (c) 2015 Rozhuk Ivan +# Copyright (c) 2020 Ingo Feinerer +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_client_subsystem("rdpsnd" "sndio" "") + +set(${MODULE_PREFIX}_SRCS + rdpsnd_sndio.c) + +include_directories(..) +include_directories(${SNDIO_INCLUDE_DIRS}) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + + + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) + +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${SNDIO_LIBRARIES}) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) + +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/SNDIO") diff --git a/channels/rdpsnd/client/sndio/rdpsnd_sndio.c b/channels/rdpsnd/client/sndio/rdpsnd_sndio.c new file mode 100644 index 0000000000..0fea5b8989 --- /dev/null +++ b/channels/rdpsnd/client/sndio/rdpsnd_sndio.c @@ -0,0 +1,220 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Output Virtual Channel + * + * Copyright 2019 Armin Novak + * Copyright 2019 Thincast Technologies GmbH + * Copyright 2020 Ingo Feinerer + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "rdpsnd_main.h" + +typedef struct rdpsnd_sndio_plugin rdpsndSndioPlugin; + +struct rdpsnd_sndio_plugin +{ + rdpsndDevicePlugin device; + + struct sio_hdl *hdl; + struct sio_par par; +}; + +static BOOL rdpsnd_sndio_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +{ + rdpsndSndioPlugin* sndio = (rdpsndSndioPlugin*)device; + + if (device == NULL || format == NULL) + return FALSE; + + if (sndio->hdl != NULL) + return TRUE; + + sndio->hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0); + if (sndio->hdl == NULL) { + WLog_ERR(TAG, "could not open audio device"); + return FALSE; + } + + sio_initpar(&sndio->par); + sndio->par.bits = format->wBitsPerSample; + sndio->par.pchan = format->nChannels; + sndio->par.rate = format->nSamplesPerSec; + if (!sio_setpar(sndio->hdl, &sndio->par)) { + WLog_ERR(TAG, "could not set audio parameters"); + return FALSE; + } + if (!sio_getpar(sndio->hdl, &sndio->par)) { + WLog_ERR(TAG, "could not get audio parameters"); + return FALSE; + } + + if (!sio_start(sndio->hdl)) { + WLog_ERR(TAG, "could not start audio device"); + return FALSE; + } + + return TRUE; +} + +static void rdpsnd_sndio_close(rdpsndDevicePlugin* device) +{ + rdpsndSndioPlugin* sndio = (rdpsndSndioPlugin*)device; + + if (device == NULL) + return; + + if (sndio->hdl != NULL) { + sio_stop(sndio->hdl); + sio_close(sndio->hdl); + sndio->hdl = NULL; + } +} + +static BOOL rdpsnd_sndio_set_volume(rdpsndDevicePlugin* device, UINT32 value) +{ + rdpsndSndioPlugin* sndio = (rdpsndSndioPlugin*)device; + + if (device == NULL || sndio->hdl == NULL) + return FALSE; + + /* + * Low-order word contains the left-channel volume setting. + * We ignore the right-channel volume setting in the high-order word. + */ + return sio_setvol(sndio->hdl, ((value & 0xFFFF) * SIO_MAXVOL) / 0xFFFF); +} + +static void rdpsnd_sndio_free(rdpsndDevicePlugin* device) +{ + rdpsndSndioPlugin* sndio = (rdpsndSndioPlugin*)device; + + if (device == NULL) + return; + + rdpsnd_sndio_close(device); + free(sndio); +} + +static BOOL rdpsnd_sndio_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +{ + if (format == NULL) + return FALSE; + + return (format->wFormatTag == WAVE_FORMAT_PCM); +} + +static void rdpsnd_sndio_play(rdpsndDevicePlugin* device, BYTE* data, int size) +{ + rdpsndSndioPlugin* sndio = (rdpsndSndioPlugin*)device; + + if (device == NULL || sndio->hdl == NULL) + return; + + sio_write(sndio->hdl, data, size); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpsnd_sndio_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args) +{ + int status; + DWORD flags; + COMMAND_LINE_ARGUMENT_A* arg; + rdpsndSndioPlugin* sndio = (rdpsndSndioPlugin*)device; + COMMAND_LINE_ARGUMENT_A rdpsnd_sndio_args[] = { { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, + rdpsnd_sndio_args, flags, sndio, NULL, NULL); + + if (status < 0) + return ERROR_INVALID_DATA; + + arg = rdpsnd_sndio_args; + + do + { + if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + continue; + + CommandLineSwitchStart(arg) CommandLineSwitchEnd(arg) + } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + return CHANNEL_RC_OK; +} + +#ifdef BUILTIN_CHANNELS +#define freerdp_rdpsnd_client_subsystem_entry sndio_freerdp_rdpsnd_client_subsystem_entry +#else +#define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) +{ + ADDIN_ARGV* args; + rdpsndSndioPlugin* sndio; + UINT ret = CHANNEL_RC_OK; + sndio = (rdpsndSndioPlugin*)calloc(1, sizeof(rdpsndSndioPlugin)); + + if (sndio == NULL) + return CHANNEL_RC_NO_MEMORY; + + sndio->device.Open = rdpsnd_sndio_open; + sndio->device.FormatSupported = rdpsnd_sndio_format_supported; + sndio->device.SetVolume = rdpsnd_sndio_set_volume; + sndio->device.Play = rdpsnd_sndio_play; + sndio->device.Close = rdpsnd_sndio_close; + sndio->device.Free = rdpsnd_sndio_free; + args = pEntryPoints->args; + + if (args->argc > 1) + { + ret = rdpsnd_sndio_parse_addin_args((rdpsndDevicePlugin*)sndio, args); + + if (ret != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "error parsing arguments"); + goto error; + } + } + + pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, &sndio->device); + return ret; +error: + rdpsnd_sndio_free(&sndio->device); + return ret; +} diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt index d4588e10bc..cc8f277691 100644 --- a/client/common/CMakeLists.txt +++ b/client/common/CMakeLists.txt @@ -68,7 +68,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) target_link_libraries(${MODULE_NAME} ${PRIVATE_KEYWORD} ${FREERDP_CHANNELS_CLIENT_LIBS}) if(OPENBSD) - target_link_libraries(${MODULE_NAME} ${PUBLIC_KEYWORD} ${${MODULE_PREFIX}_LIBS} ossaudio) + target_link_libraries(${MODULE_NAME} ${PUBLIC_KEYWORD} ${${MODULE_PREFIX}_LIBS} sndio) else() target_link_libraries(${MODULE_NAME} ${PUBLIC_KEYWORD} ${${MODULE_PREFIX}_LIBS}) endif()