Added support for WAVE2 PDU in server side audio channel.
authorArmin Novak <armin.novak@thincast.com>
Mon, 2 Jul 2018 14:08:47 +0000 (16:08 +0200)
committerArmin Novak <armin.novak@thincast.com>
Mon, 2 Jul 2018 14:20:39 +0000 (16:20 +0200)
channels/rdpsnd/CMakeLists.txt
channels/rdpsnd/client/CMakeLists.txt
channels/rdpsnd/client/rdpsnd_main.c
channels/rdpsnd/common/CMakeLists.txt [new file with mode: 0644]
channels/rdpsnd/common/rdpsnd_common.c [new file with mode: 0644]
channels/rdpsnd/common/rdpsnd_common.h [new file with mode: 0644]
channels/rdpsnd/server/CMakeLists.txt
channels/rdpsnd/server/rdpsnd_main.c
include/freerdp/server/rdpsnd.h

index 44a46fe..08b6836 100644 (file)
@@ -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()
index 2c35ac2..fc6e999 100644 (file)
@@ -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")
 
index 44f572a..bd595d6 100644 (file)
@@ -47,6 +47,7 @@
 #include <freerdp/addin.h>
 #include <freerdp/codec/dsp.h>
 
+#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 (file)
index 0000000..e66a299
--- /dev/null
@@ -0,0 +1,23 @@
+# FreeRDP: A Remote Desktop Protocol Implementation
+# FreeRDP cmake build script
+#
+# Copyright 2018 Armin Novak <armin.novak@thincast.com>
+# 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 (file)
index 0000000..d49f6b4
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * Server Audio Virtual Channel
+ *
+ * Copyright 2018 Armin Novak <armin.novak@thincast.com>
+ * 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 (file)
index 0000000..6afcbc7
--- /dev/null
@@ -0,0 +1,43 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * Server Audio Virtual Channel
+ *
+ * Copyright 2018 Armin Novak <armin.novak@thincast.com>
+ * 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 <winpr/crt.h>
+#include <winpr/synch.h>
+#include <winpr/thread.h>
+
+#include <freerdp/codec/dsp.h>
+#include <freerdp/channels/wtsvc.h>
+#include <freerdp/channels/log.h>
+#include <freerdp/server/rdpsnd.h>
+
+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 */
index 62d57be..c08d081 100644 (file)
@@ -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")
index 3f5b816..0824f0e 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <freerdp/channels/log.h>
 
+#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;
index 463469d..64f4805 100644 (file)
@@ -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