diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 01:24:41 +0000 |
commit | a9bcc81f821d7c66f623779fa5147e728eb3c388 (patch) | |
tree | 98676963bcdd537ae5908a067a8eb110b93486a6 /channels/rdpsnd/client/sndio | |
parent | Initial commit. (diff) | |
download | freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.tar.xz freerdp3-a9bcc81f821d7c66f623779fa5147e728eb3c388.zip |
Adding upstream version 3.3.0+dfsg1.upstream/3.3.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'channels/rdpsnd/client/sndio')
-rw-r--r-- | channels/rdpsnd/client/sndio/CMakeLists.txt | 36 | ||||
-rw-r--r-- | channels/rdpsnd/client/sndio/rdpsnd_sndio.c | 217 |
2 files changed, 253 insertions, 0 deletions
diff --git a/channels/rdpsnd/client/sndio/CMakeLists.txt b/channels/rdpsnd/client/sndio/CMakeLists.txt new file mode 100644 index 0000000..78b9c06 --- /dev/null +++ b/channels/rdpsnd/client/sndio/CMakeLists.txt @@ -0,0 +1,36 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright (c) 2015 Rozhuk Ivan <rozhuk.im@gmail.com> +# Copyright (c) 2020 Ingo Feinerer <feinerer@logic.at> +# +# 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" "") + +find_package(SNDIO REQUIRED) + +set(${MODULE_PREFIX}_SRCS + rdpsnd_sndio.c +) + +set(${MODULE_PREFIX}_LIBS + winpr + freerdp + ${SNDIO_LIBRARIES} +) + +include_directories(..) +include_directories(${SNDIO_INCLUDE_DIRS}) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") diff --git a/channels/rdpsnd/client/sndio/rdpsnd_sndio.c b/channels/rdpsnd/client/sndio/rdpsnd_sndio.c new file mode 100644 index 0000000..4414653 --- /dev/null +++ b/channels/rdpsnd/client/sndio/rdpsnd_sndio.c @@ -0,0 +1,217 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Output Virtual Channel + * + * Copyright 2019 Armin Novak <armin.novak@thincast.com> + * Copyright 2019 Thincast Technologies GmbH + * Copyright 2020 Ingo Feinerer <feinerer@logic.at> + * + * 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. + */ + +#include <freerdp/config.h> + +#include <sndio.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <winpr/crt.h> +#include <winpr/stream.h> +#include <winpr/cmdline.h> + +#include <freerdp/types.h> + +#include "rdpsnd_main.h" + +typedef struct +{ + rdpsndDevicePlugin device; + + struct sio_hdl* hdl; + struct sio_par par; +} rdpsndSndioPlugin; + +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; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +FREERDP_ENTRY_POINT(UINT sndio_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; +} |