From 373bfac9abcedda31055afe285c38ca9d8700a44 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 2 Jul 2018 16:08:47 +0200 Subject: [PATCH] Added support for WAVE2 PDU in server side audio channel. --- channels/rdpsnd/CMakeLists.txt | 3 ++ channels/rdpsnd/client/CMakeLists.txt | 5 +- channels/rdpsnd/client/rdpsnd_main.c | 5 +- channels/rdpsnd/common/CMakeLists.txt | 23 +++++++++ channels/rdpsnd/common/rdpsnd_common.c | 20 ++++++++ channels/rdpsnd/common/rdpsnd_common.h | 43 ++++++++++++++++ channels/rdpsnd/server/CMakeLists.txt | 5 +- channels/rdpsnd/server/rdpsnd_main.c | 89 ++++++++++++++++++++++++++++++---- include/freerdp/server/rdpsnd.h | 31 ++++++------ 9 files changed, 192 insertions(+), 32 deletions(-) create mode 100644 channels/rdpsnd/common/CMakeLists.txt create mode 100644 channels/rdpsnd/common/rdpsnd_common.c create mode 100644 channels/rdpsnd/common/rdpsnd_common.h diff --git a/channels/rdpsnd/CMakeLists.txt b/channels/rdpsnd/CMakeLists.txt index 44a46fe..08b6836 100644 --- a/channels/rdpsnd/CMakeLists.txt +++ b/channels/rdpsnd/CMakeLists.txt @@ -17,6 +17,9 @@ define_channel("rdpsnd") +include_directories(common) +add_subdirectory(common) + if(WITH_CLIENT_CHANNELS) add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() diff --git a/channels/rdpsnd/client/CMakeLists.txt b/channels/rdpsnd/client/CMakeLists.txt index 2c35ac2..fc6e999 100644 --- a/channels/rdpsnd/client/CMakeLists.txt +++ b/channels/rdpsnd/client/CMakeLists.txt @@ -23,7 +23,10 @@ set(${MODULE_PREFIX}_SRCS add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx") -target_link_libraries(${MODULE_NAME} winpr freerdp ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(${MODULE_NAME} + winpr freerdp ${CMAKE_THREAD_LIBS_INIT} + ${CMAKE_CURRENT_BINARY_DIR}/../common/rdpsnd-common${CMAKE_STATIC_LIBRARY_SUFFIX} +) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 44f572a..bd595d6 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -47,6 +47,7 @@ #include #include +#include "rdpsnd_common.h" #include "rdpsnd_main.h" struct rdpsnd_plugin @@ -219,7 +220,7 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) Stream_Write_UINT16(pdu, 0); /* wDGramPort */ Stream_Write_UINT16(pdu, wNumberOfFormats); /* wNumberOfFormats */ Stream_Write_UINT8(pdu, 0); /* cLastBlockConfirmed */ - Stream_Write_UINT16(pdu, 0x8); /* wVersion */ + Stream_Write_UINT16(pdu, CHANNEL_VERSION_WIN_MAX); /* wVersion */ Stream_Write_UINT8(pdu, 0); /* bPad */ for (index = 0; index < wNumberOfFormats; index++) @@ -318,7 +319,7 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, if (ret == CHANNEL_RC_OK) { - if (wVersion >= 6) + if (wVersion >= CHANNEL_VERSION_WIN_7) ret = rdpsnd_send_quality_mode_pdu(rdpsnd); } diff --git a/channels/rdpsnd/common/CMakeLists.txt b/channels/rdpsnd/common/CMakeLists.txt new file mode 100644 index 0000000..e66a299 --- /dev/null +++ b/channels/rdpsnd/common/CMakeLists.txt @@ -0,0 +1,23 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2018 Armin Novak +# Copyright 2018 Thincast Technologies GmbH +# +# 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. + +set(SRCS + rdpsnd_common.h + rdpsnd_common.c) + +add_library(rdpsnd-common STATIC ${SRCS}) diff --git a/channels/rdpsnd/common/rdpsnd_common.c b/channels/rdpsnd/common/rdpsnd_common.c new file mode 100644 index 0000000..d49f6b4 --- /dev/null +++ b/channels/rdpsnd/common/rdpsnd_common.c @@ -0,0 +1,20 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Server Audio Virtual Channel + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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 "rdpsnd_common.h" diff --git a/channels/rdpsnd/common/rdpsnd_common.h b/channels/rdpsnd/common/rdpsnd_common.h new file mode 100644 index 0000000..6afcbc7 --- /dev/null +++ b/channels/rdpsnd/common/rdpsnd_common.h @@ -0,0 +1,43 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Server Audio Virtual Channel + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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. + */ + +#ifndef FREERDP_CHANNEL_RDPSND_COMMON_MAIN_H +#define FREERDP_CHANNEL_RDPSND_COMMON_MAIN_H + +#include +#include +#include + +#include +#include +#include +#include + +typedef enum +{ + CHANNEL_VERSION_WIN_XP = 0x02, + CHANNEL_VERSION_WIN_XP_SP1 = 0x05, + CHANNEL_VERSION_WIN_VISTA = 0x05, + CHANNEL_VERSION_WIN_7 = 0x06, + CHANNEL_VERSION_WIN_8 = 0x08, + CHANNEL_VERSION_WIN_MAX = CHANNEL_VERSION_WIN_8 +} RdpSndChannelVersion; + +#endif /* FREERDP_CHANNEL_RDPSND_COMMON_MAIN_H */ diff --git a/channels/rdpsnd/server/CMakeLists.txt b/channels/rdpsnd/server/CMakeLists.txt index 62d57be..c08d081 100644 --- a/channels/rdpsnd/server/CMakeLists.txt +++ b/channels/rdpsnd/server/CMakeLists.txt @@ -23,9 +23,6 @@ set(${MODULE_PREFIX}_SRCS add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") - - -target_link_libraries(${MODULE_NAME} freerdp) - +target_link_libraries(${MODULE_NAME} freerdp ${CMAKE_CURRENT_BINARY_DIR}/../common/rdpsnd-common${CMAKE_STATIC_LIBRARY_SUFFIX}) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index 3f5b816..0824f0e 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -33,6 +33,7 @@ #include +#include "rdpsnd_common.h" #include "rdpsnd_main.h" /** @@ -40,7 +41,7 @@ * * @return 0 on success, otherwise a Win32 error code */ -UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) +static UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) { size_t pos; UINT16 i; @@ -55,7 +56,7 @@ UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) Stream_Write_UINT16(s, 0); /* wDGramPort */ Stream_Write_UINT16(s, context->num_server_formats); /* wNumberOfFormats */ Stream_Write_UINT8(s, context->block_no); /* cLastBlockConfirmed */ - Stream_Write_UINT16(s, 0x06); /* wVersion */ + Stream_Write_UINT16(s, CHANNEL_VERSION_WIN_MAX); /* wVersion */ Stream_Write_UINT8(s, 0); /* bPad */ for (i = 0; i < context->num_server_formats; i++) @@ -65,8 +66,8 @@ UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) Stream_Write_UINT16(s, context->server_formats[i].nChannels); /* nChannels */ Stream_Write_UINT32(s, context->server_formats[i].nSamplesPerSec); /* nSamplesPerSec */ - Stream_Write_UINT32(s, context->server_formats[i].nSamplesPerSec * - context->server_formats[i].nChannels * + Stream_Write_UINT32(s, context->server_formats[i].nSamplesPerSec* + context->server_formats[i].nChannels* context->server_formats[i].wBitsPerSample / 8); /* nAvgBytesPerSec */ Stream_Write_UINT16(s, context->server_formats[i].nBlockAlign); /* nBlockAlign */ @@ -149,7 +150,7 @@ static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, */ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) { - int i, num_known_format = 0; + UINT16 i, num_known_format = 0; UINT32 flags, vol, pitch; UINT16 udpPort; BYTE lastblock; @@ -314,7 +315,7 @@ static UINT rdpsnd_server_initialize(RdpsndServerContext* context, * @return 0 on success, otherwise a Win32 error code */ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, - int client_format_index) + UINT16 client_format_index) { int bs; int out_buffer_size; @@ -404,8 +405,8 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, - UINT16 wTimestamp) +static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, + UINT16 wTimestamp) { size_t length; size_t start, end = 0; @@ -470,6 +471,74 @@ out: /** * Function description + * context->priv->lock should be obtained before calling this function + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, + UINT16 wTimestamp) +{ + size_t length; + size_t end = 0; + const BYTE* src; + BOOL status; + AUDIO_FORMAT* format; + ULONG written; + wStream* s = context->priv->rdpsnd_pdu; + UINT error = CHANNEL_RC_OK; + format = &context->client_formats[context->selected_client_format]; + /* WaveInfo PDU */ + Stream_SetPosition(s, 0); + Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */ + Stream_Write_UINT8(s, 0); /* bPad */ + Stream_Write_UINT16(s, 0); /* BodySize */ + Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */ + Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */ + Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ + Stream_Seek(s, 3); /* bPad */ + Stream_Write_UINT16(s, wTimestamp); /* dwAudioTimeStamp */ + src = context->priv->out_buffer; + length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; + + if (!freerdp_dsp_encode(context->priv->dsp_context, format, src, length, s)) + status = ERROR_INTERNAL_ERROR; + else + { + /* Set stream size */ + end = Stream_GetPosition(s); + Stream_SetPosition(s, 2); + Stream_Write_UINT16(s, end); + Stream_SetPosition(s, end); + Stream_SealLength(s); + context->block_no = (context->block_no + 1) % 256; + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, + (PCHAR) Stream_Buffer(s), Stream_Length(s), &written); + } + + if (!status) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + error = ERROR_INTERNAL_ERROR; + } + +out: + Stream_SetPosition(s, 0); + context->priv->out_pending_frames = 0; + return error; +} + +/* Wrapper function to send WAVE or WAVE2 PDU depending on client connected */ +static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, + UINT16 wTimestamp) +{ + if (context->clientVersion >= CHANNEL_VERSION_WIN_8) + return rdpsnd_server_send_wave2_pdu(context, wTimestamp); + else + return rdpsnd_server_send_wave_pdu(context, wTimestamp); +} + +/** + * Function description * * @return 0 on success, otherwise a Win32 error code */ @@ -876,7 +945,7 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) case SNDC_FORMATS: ret = rdpsnd_server_recv_formats(context, s); - if ((ret == CHANNEL_RC_OK) && (context->clientVersion < 6)) + if ((ret == CHANNEL_RC_OK) && (context->clientVersion < CHANNEL_VERSION_WIN_7)) IFCALL(context->Activated, context); break; @@ -886,7 +955,7 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) Stream_SetPosition(s, 0); /* in case the Activated callback tries to treat some messages */ - if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= 6)) + if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7)) IFCALL(context->Activated, context); break; diff --git a/include/freerdp/server/rdpsnd.h b/include/freerdp/server/rdpsnd.h index 463469d..64f4805 100644 --- a/include/freerdp/server/rdpsnd.h +++ b/include/freerdp/server/rdpsnd.h @@ -29,15 +29,17 @@ typedef struct _rdpsnd_server_context RdpsndServerContext; typedef struct _rdpsnd_server_context rdpsnd_server_context; typedef struct _rdpsnd_server_private RdpsndServerPrivate; -typedef UINT (*psRdpsndStart)(RdpsndServerContext* context); -typedef UINT (*psRdpsndStop)(RdpsndServerContext* context); +typedef UINT(*psRdpsndStart)(RdpsndServerContext* context); +typedef UINT(*psRdpsndStop)(RdpsndServerContext* context); -typedef UINT (*psRdpsndServerInitialize)(RdpsndServerContext* context, BOOL ownThread); -typedef UINT (*psRdpsndServerSelectFormat)(RdpsndServerContext* context, int client_format_index); -typedef UINT (*psRdpsndServerSendSamples)(RdpsndServerContext* context, const void* buf, int nframes, UINT16 wTimestamp); -typedef UINT (*psRdpsndServerConfirmBlock)(RdpsndServerContext* context, BYTE confirmBlockNum, UINT16 wtimestamp); -typedef UINT (*psRdpsndServerSetVolume)(RdpsndServerContext* context, int left, int right); -typedef UINT (*psRdpsndServerClose)(RdpsndServerContext* context); +typedef UINT(*psRdpsndServerInitialize)(RdpsndServerContext* context, BOOL ownThread); +typedef UINT(*psRdpsndServerSelectFormat)(RdpsndServerContext* context, UINT16 client_format_index); +typedef UINT(*psRdpsndServerSendSamples)(RdpsndServerContext* context, const void* buf, int nframes, + UINT16 wTimestamp); +typedef UINT(*psRdpsndServerConfirmBlock)(RdpsndServerContext* context, BYTE confirmBlockNum, + UINT16 wtimestamp); +typedef UINT(*psRdpsndServerSetVolume)(RdpsndServerContext* context, int left, int right); +typedef UINT(*psRdpsndServerClose)(RdpsndServerContext* context); typedef void (*psRdpsndServerActivated)(RdpsndServerContext* context); @@ -66,11 +68,11 @@ struct _rdpsnd_server_context /* Client supported formats. */ AUDIO_FORMAT* client_formats; - int num_client_formats; - int selected_client_format; + UINT16 num_client_formats; + UINT16 selected_client_format; /* Last sent audio block number. */ - int block_no; + UINT8 block_no; /*** APIs called by the server. ***/ /** @@ -124,11 +126,10 @@ extern "C" { #endif FREERDP_API RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm); -FREERDP_API void rdpsnd_server_context_reset(RdpsndServerContext *); +FREERDP_API void rdpsnd_server_context_reset(RdpsndServerContext*); FREERDP_API void rdpsnd_server_context_free(RdpsndServerContext* context); -FREERDP_API HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext *context); -FREERDP_API UINT rdpsnd_server_handle_messages(RdpsndServerContext *context); -FREERDP_API UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s); +FREERDP_API HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context); +FREERDP_API UINT rdpsnd_server_handle_messages(RdpsndServerContext* context); #ifdef __cplusplus -- 2.7.4