define_channel("rdpsnd")
+include_directories(common)
+add_subdirectory(common)
+
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
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")
#include <freerdp/addin.h>
#include <freerdp/codec/dsp.h>
+#include "rdpsnd_common.h"
#include "rdpsnd_main.h"
struct rdpsnd_plugin
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++)
if (ret == CHANNEL_RC_OK)
{
- if (wVersion >= 6)
+ if (wVersion >= CHANNEL_VERSION_WIN_7)
ret = rdpsnd_send_quality_mode_pdu(rdpsnd);
}
--- /dev/null
+# 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})
--- /dev/null
+/**
+ * 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"
--- /dev/null
+/**
+ * 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 */
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")
#include <freerdp/channels/log.h>
+#include "rdpsnd_common.h"
#include "rdpsnd_main.h"
/**
*
* @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;
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++)
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 */
*/
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;
* @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;
*
* @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;
/**
* 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
*/
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;
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;
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);
/* 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. ***/
/**
#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