Merge pull request #4724 from akallabeth/wave2_server

Wave2 server side support
This commit is contained in:
David Fort 2018-07-04 13:10:38 +02:00 committed by GitHub
commit a1d9399ca0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 238 additions and 56 deletions

View File

@ -183,7 +183,6 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
UINT error;
wStream* out;
UINT32 NumFormats;
AUDIO_FORMAT format;
UINT32 cbSizeFormatsPacket;
if (Stream_GetRemainingLength(s) < 8)
@ -221,12 +220,11 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
/* SoundFormats (variable) */
for (i = 0; i < NumFormats; i++)
{
BYTE* fm;
AUDIO_FORMAT format = { 0 };
if (Stream_GetRemainingLength(s) < 18)
return ERROR_INVALID_DATA;
Stream_GetPointer(s, fm);
Stream_Read_UINT16(s, format.wFormatTag);
Stream_Read_UINT16(s, format.nChannels);
Stream_Read_UINT32(s, format.nSamplesPerSec);
@ -234,12 +232,21 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
Stream_Read_UINT16(s, format.nBlockAlign);
Stream_Read_UINT16(s, format.wBitsPerSample);
Stream_Read_UINT16(s, format.cbSize);
format.data = Stream_Pointer(s);
if (Stream_GetRemainingLength(s) < format.cbSize)
return ERROR_INVALID_DATA;
Stream_Seek(s, format.cbSize);
if (format.cbSize > 0)
{
format.data = malloc(format.cbSize);
if (!format.data)
return ERROR_OUTOFMEMORY;
memcpy(format.data, Stream_Pointer(s), format.cbSize);
Stream_Seek(s, format.cbSize);
}
DEBUG_DVC("wFormatTag=%"PRIu16" nChannels=%"PRIu16" nSamplesPerSec=%"PRIu32" "
"nBlockAlign=%"PRIu16" wBitsPerSample=%"PRIu16" cbSize=%"PRIu16"",
format.wFormatTag, format.nChannels, format.nSamplesPerSec,
@ -268,7 +275,12 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback,
goto out;
}
Stream_Write(out, fm, 18 + format.cbSize);
Stream_Write(out, &format, 18);
Stream_Write(out, format.data, format.cbSize);
}
else
{
free(format.data);
}
}
@ -289,8 +301,16 @@ out:
if (error != CHANNEL_RC_OK)
{
free(callback->formats);
callback->formats = NULL;
size_t x;
if (callback->formats)
{
for (x = 0; x < NumFormats; x++)
free(callback->formats[x].data);
free(callback->formats);
callback->formats = NULL;
}
}
return error;
@ -504,7 +524,7 @@ static UINT audin_process_format_change(IWTSVirtualChannelCallback* pChannelCall
Stream_Read_UINT32(s, NewFormat);
DEBUG_DVC("NewFormat=%"PRIu32"", NewFormat);
if (NewFormat >= (UINT32) callback->formats_count)
if (NewFormat >= callback->formats_count)
{
WLog_ERR(TAG, "invalid format index %"PRIu32" (total %d)",
NewFormat, callback->formats_count);
@ -583,6 +603,7 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
*/
static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
{
size_t x;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
UINT error = CHANNEL_RC_OK;
@ -597,7 +618,18 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
}
audin->format = NULL;
free(callback->formats);
if (callback->formats)
{
for (x = 0; x < callback->formats_count; x++)
{
AUDIO_FORMAT* format = &callback->formats[x];
free(format->data);
}
free(callback->formats);
}
free(callback);
return error;
}

View 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()

View File

@ -23,7 +23,9 @@ 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}
)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")

View 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);
}

View File

@ -0,0 +1,24 @@
# 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)
# Library currently header only
#add_library(rdpsnd-common STATIC ${SRCS})

View File

@ -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 */

View File

@ -23,9 +23,4 @@ set(${MODULE_PREFIX}_SRCS
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
target_link_libraries(${MODULE_NAME} freerdp)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

View 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;
@ -468,6 +469,74 @@ out:
return error;
}
/**
* 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
*
@ -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;

View 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

View File

@ -21,6 +21,8 @@
#endif
#include <freerdp/log.h>
#include <freerdp/codec/dsp.h>
#include "shadow.h"
#include "shadow_rdpsnd.h"
@ -30,29 +32,34 @@
/* Default supported audio formats */
static const AUDIO_FORMAT default_supported_audio_formats[] =
{
{ WAVE_FORMAT_AAC_MS, 2, 44100, 176400, 4, 16, 0, NULL },
{ WAVE_FORMAT_MPEGLAYER3, 2, 44100, 176400, 4, 16, 0, NULL },
{ WAVE_FORMAT_GSM610, 2, 44100, 176400, 4, 16, 0, NULL },
{ WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0, NULL },
{ WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, 0, NULL }
{ WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, 0, NULL },
};
static AUDIO_FORMAT supported_audio_formats[ARRAYSIZE(default_supported_audio_formats)] = { 0 };
static void rdpsnd_activated(RdpsndServerContext* context)
{
AUDIO_FORMAT* agreed_format = NULL;
int i = 0, j = 0;
UINT16 i = 0, j = 0;
for (i = 0; i < context->num_client_formats; i++)
{
for (j = 0; j < context->num_server_formats; j++)
{
if ((context->client_formats[i].wFormatTag == context->server_formats[j].wFormatTag) &&
(context->client_formats[i].nChannels == context->server_formats[j].nChannels) &&
(context->client_formats[i].nSamplesPerSec == context->server_formats[j].nSamplesPerSec))
(context->client_formats[i].nChannels == context->server_formats[j].nChannels) &&
(context->client_formats[i].nSamplesPerSec == context->server_formats[j].nSamplesPerSec))
{
agreed_format = (AUDIO_FORMAT*) &context->server_formats[j];
break;
}
}
if (agreed_format != NULL)
break;
}
if (agreed_format == NULL)
@ -67,8 +74,8 @@ static void rdpsnd_activated(RdpsndServerContext* context)
int shadow_client_rdpsnd_init(rdpShadowClient* client)
{
RdpsndServerContext* rdpsnd;
rdpsnd = client->rdpsnd = rdpsnd_server_context_new(client->vcm);
if (!rdpsnd)
{
return 0;
@ -83,20 +90,25 @@ int shadow_client_rdpsnd_init(rdpShadowClient* client)
}
else
{
size_t x, y = 0;
for (x = 0; x < ARRAYSIZE(default_supported_audio_formats); x++)
{
const AUDIO_FORMAT* format = &default_supported_audio_formats[x];
if (freerdp_dsp_supports_format(format, TRUE))
supported_audio_formats[y++] = *format;
}
/* Set default audio formats. */
rdpsnd->server_formats = default_supported_audio_formats;
rdpsnd->num_server_formats =
sizeof(default_supported_audio_formats) / sizeof(default_supported_audio_formats[0]);
rdpsnd->server_formats = supported_audio_formats;
rdpsnd->num_server_formats = y;
}
rdpsnd->src_format = rdpsnd->server_formats[0];
rdpsnd->Activated = rdpsnd_activated;
rdpsnd->Initialize(rdpsnd, TRUE);
return 1;
}
void shadow_client_rdpsnd_uninit(rdpShadowClient* client)