diff --git a/channels/rdpsnd/server/rdpsnd.c b/channels/rdpsnd/server/rdpsnd.c deleted file mode 100644 index 2735156c9..000000000 --- a/channels/rdpsnd/server/rdpsnd.c +++ /dev/null @@ -1,563 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Server Audio Virtual Channel - * - * Copyright 2012 Vic Lee - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -typedef struct _rdpsnd_server -{ - rdpsnd_server_context context; - - HANDLE thread; - HANDLE StopEvent; - void* rdpsnd_channel; - wStream* rdpsnd_pdu; - - FREERDP_DSP_CONTEXT* dsp_context; - BYTE* out_buffer; - int out_buffer_size; - int out_frames; - int out_pending_frames; - - UINT32 src_bytes_per_sample; - UINT32 src_bytes_per_frame; -} rdpsnd_server; - - -static BOOL rdpsnd_server_send_formats(rdpsnd_server* rdpsnd, wStream* s) -{ - int pos; - UINT16 i; - BOOL status; - - Stream_Write_UINT8(s, SNDC_FORMATS); - Stream_Write_UINT8(s, 0); - Stream_Seek_UINT16(s); - - Stream_Write_UINT32(s, 0); /* dwFlags */ - Stream_Write_UINT32(s, 0); /* dwVolume */ - Stream_Write_UINT32(s, 0); /* dwPitch */ - Stream_Write_UINT16(s, 0); /* wDGramPort */ - Stream_Write_UINT16(s, rdpsnd->context.num_server_formats); /* wNumberOfFormats */ - Stream_Write_UINT8(s, rdpsnd->context.block_no); /* cLastBlockConfirmed */ - Stream_Write_UINT16(s, 0x06); /* wVersion */ - Stream_Write_UINT8(s, 0); /* bPad */ - - for (i = 0; i < rdpsnd->context.num_server_formats; i++) - { - Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].wFormatTag); /* wFormatTag (WAVE_FORMAT_PCM) */ - Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].nChannels); /* nChannels */ - Stream_Write_UINT32(s, rdpsnd->context.server_formats[i].nSamplesPerSec); /* nSamplesPerSec */ - - Stream_Write_UINT32(s, rdpsnd->context.server_formats[i].nSamplesPerSec * - rdpsnd->context.server_formats[i].nChannels * - rdpsnd->context.server_formats[i].wBitsPerSample / 8); /* nAvgBytesPerSec */ - - Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].nBlockAlign); /* nBlockAlign */ - Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].wBitsPerSample); /* wBitsPerSample */ - Stream_Write_UINT16(s, rdpsnd->context.server_formats[i].cbSize); /* cbSize */ - - if (rdpsnd->context.server_formats[i].cbSize > 0) - { - Stream_Write(s, rdpsnd->context.server_formats[i].data, rdpsnd->context.server_formats[i].cbSize); - } - } - - pos = Stream_GetPosition(s); - Stream_SetPosition(s, 2); - Stream_Write_UINT16(s, pos - 4); - Stream_SetPosition(s, pos); - status = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL); - Stream_SetPosition(s, 0); - - return status; -} - -static void rdpsnd_server_recv_waveconfirm(rdpsnd_server* rdpsnd, wStream* s) -{ - //unhandled for now - - UINT16 timestamp = 0; - BYTE confirmBlockNum = 0; - Stream_Read_UINT16(s, timestamp); - Stream_Read_UINT8(s, confirmBlockNum); - Stream_Seek_UINT8(s); // padding -} - -static void rdpsnd_server_recv_quality_mode(rdpsnd_server* rdpsnd, wStream* s) -{ - //unhandled for now - UINT16 quality; - - Stream_Read_UINT16(s, quality); - Stream_Seek_UINT16(s); // reserved - - fprintf(stderr, "Client requested sound quality: %#0X\n", quality); -} - -static BOOL rdpsnd_server_recv_formats(rdpsnd_server* rdpsnd, wStream* s) -{ - int i, num_known_format = 0; - UINT32 flags, vol, pitch; - UINT16 udpPort, version; - BYTE lastblock; - - - Stream_Read_UINT32(s, flags); /* dwFlags */ - Stream_Read_UINT32(s, vol); /* dwVolume */ - Stream_Read_UINT32(s, pitch); /* dwPitch */ - Stream_Read_UINT16(s, udpPort); /* wDGramPort */ - Stream_Read_UINT16(s, rdpsnd->context.num_client_formats); /* wNumberOfFormats */ - Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */ - Stream_Read_UINT16(s, version); /* wVersion */ - Stream_Seek_UINT8(s); /* bPad */ - - if (rdpsnd->context.num_client_formats > 0) - { - rdpsnd->context.client_formats = (AUDIO_FORMAT*) malloc(rdpsnd->context.num_client_formats * sizeof(AUDIO_FORMAT)); - ZeroMemory(rdpsnd->context.client_formats, sizeof(AUDIO_FORMAT)); - - for (i = 0; i < rdpsnd->context.num_client_formats; i++) - { - Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].wFormatTag); - Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].nChannels); - Stream_Read_UINT32(s, rdpsnd->context.client_formats[i].nSamplesPerSec); - Stream_Read_UINT32(s, rdpsnd->context.client_formats[i].nAvgBytesPerSec); - Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].nBlockAlign); - Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].wBitsPerSample); - Stream_Read_UINT16(s, rdpsnd->context.client_formats[i].cbSize); - - if (rdpsnd->context.client_formats[i].cbSize > 0) - { - Stream_Seek(s, rdpsnd->context.client_formats[i].cbSize); - } - - if (rdpsnd->context.client_formats[i].wFormatTag != 0) - { - //lets call this a known format - //TODO: actually look through our own list of known formats - num_known_format++; - } - } - } - - if (num_known_format == 0) - { - fprintf(stderr, "Client doesnt support any known formats!\n"); - return FALSE; - } - - return TRUE; -} - -static void* rdpsnd_server_thread_func(void* arg) -{ - void* fd; - wStream* s; - void* buffer; - DWORD status; - BYTE msgType; - UINT16 BodySize; - HANDLE events[2]; - UINT32 bytes_returned = 0; - rdpsnd_server* rdpsnd = (rdpsnd_server*) arg; - - events[0] = rdpsnd->StopEvent; - - if (WTSVirtualChannelQuery(rdpsnd->rdpsnd_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == TRUE) - { - fd = *((void**) buffer); - WTSFreeMemory(buffer); - - events[1] = CreateWaitObjectEvent(NULL, TRUE, FALSE, fd); - } - - s = Stream_New(NULL, 4096); - - rdpsnd_server_send_formats(rdpsnd, s); - - while (1) - { - status = WaitForMultipleObjects(2, events, FALSE, INFINITE); - - if (WaitForSingleObject(rdpsnd->StopEvent, 0) == WAIT_OBJECT_0) - { - break; - } - - Stream_SetPosition(s, 0); - - if (WTSVirtualChannelRead(rdpsnd->rdpsnd_channel, 0, Stream_Buffer(s), - Stream_Capacity(s), &bytes_returned) == FALSE) - { - if (bytes_returned == 0) - break; - - Stream_EnsureRemainingCapacity(s, (int) bytes_returned); - - if (WTSVirtualChannelRead(rdpsnd->rdpsnd_channel, 0, Stream_Buffer(s), - Stream_Capacity(s), &bytes_returned) == FALSE) - break; - } - - Stream_Read_UINT8(s, msgType); - Stream_Seek_UINT8(s); /* bPad */ - Stream_Read_UINT16(s, BodySize); - - switch (msgType) - { - case SNDC_WAVECONFIRM: - rdpsnd_server_recv_waveconfirm(rdpsnd, s); - break; - - case SNDC_QUALITYMODE: - rdpsnd_server_recv_quality_mode(rdpsnd, s); - break; - case SNDC_FORMATS: - if (rdpsnd_server_recv_formats(rdpsnd, s)) - { - IFCALL(rdpsnd->context.Activated, &rdpsnd->context); - } - break; - default: - fprintf(stderr, "UNKOWN MESSAGE TYPE!! (%#0X)\n\n", msgType); - break; - } - } - - Stream_Free(s, TRUE); - - return NULL; -} - -static BOOL rdpsnd_server_initialize(rdpsnd_server_context* context) -{ - rdpsnd_server* rdpsnd = (rdpsnd_server*) context; - - rdpsnd->rdpsnd_channel = WTSVirtualChannelOpenEx(context->vcm, "rdpsnd", 0); - - if (rdpsnd->rdpsnd_channel != NULL) - { - rdpsnd->rdpsnd_pdu = Stream_New(NULL, 4096); - - rdpsnd->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - rdpsnd->thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) rdpsnd_server_thread_func, (void*) rdpsnd, 0, NULL); - - return TRUE; - } - else - { - return FALSE; - } -} - -static void rdpsnd_server_select_format(rdpsnd_server_context* context, int client_format_index) -{ - int bs; - int out_buffer_size; - AUDIO_FORMAT *format; - rdpsnd_server* rdpsnd = (rdpsnd_server*) context; - - if (client_format_index < 0 || client_format_index >= context->num_client_formats) - { - fprintf(stderr, "rdpsnd_server_select_format: index %d is not correct.\n", client_format_index); - return; - } - - rdpsnd->src_bytes_per_sample = context->src_format.wBitsPerSample / 8; - rdpsnd->src_bytes_per_frame = rdpsnd->src_bytes_per_sample * context->src_format.nChannels; - - context->selected_client_format = client_format_index; - format = &context->client_formats[client_format_index]; - - if (format->nSamplesPerSec == 0) - { - fprintf(stderr, "Invalid Client Sound Format!!\n\n"); - return; - } - - if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM) - { - bs = (format->nBlockAlign - 4 * format->nChannels) * 4; - rdpsnd->out_frames = (format->nBlockAlign * 4 * format->nChannels * 2 / bs + 1) * bs / (format->nChannels * 2); - } - else if (format->wFormatTag == WAVE_FORMAT_ADPCM) - { - bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2; - rdpsnd->out_frames = bs * 4; - } - else - { - rdpsnd->out_frames = 0x4000 / rdpsnd->src_bytes_per_frame; - } - - if (format->nSamplesPerSec != context->src_format.nSamplesPerSec) - { - rdpsnd->out_frames = (rdpsnd->out_frames * context->src_format.nSamplesPerSec + format->nSamplesPerSec - 100) / format->nSamplesPerSec; - } - rdpsnd->out_pending_frames = 0; - - out_buffer_size = rdpsnd->out_frames * rdpsnd->src_bytes_per_frame; - - if (rdpsnd->out_buffer_size < out_buffer_size) - { - rdpsnd->out_buffer = (BYTE*) realloc(rdpsnd->out_buffer, out_buffer_size); - rdpsnd->out_buffer_size = out_buffer_size; - } - - freerdp_dsp_context_reset_adpcm(rdpsnd->dsp_context); -} - -static BOOL rdpsnd_server_send_audio_pdu(rdpsnd_server* rdpsnd) -{ - int size; - BYTE* src; - int frames; - int fill_size; - BOOL status; - AUDIO_FORMAT* format; - int tbytes_per_frame; - wStream* s = rdpsnd->rdpsnd_pdu; - - format = &rdpsnd->context.client_formats[rdpsnd->context.selected_client_format]; - tbytes_per_frame = format->nChannels * rdpsnd->src_bytes_per_sample; - - if ((format->nSamplesPerSec == rdpsnd->context.src_format.nSamplesPerSec) && - (format->nChannels == rdpsnd->context.src_format.nChannels)) - { - src = rdpsnd->out_buffer; - frames = rdpsnd->out_pending_frames; - } - else - { - rdpsnd->dsp_context->resample(rdpsnd->dsp_context, rdpsnd->out_buffer, rdpsnd->src_bytes_per_sample, - rdpsnd->context.src_format.nChannels, rdpsnd->context.src_format.nSamplesPerSec, rdpsnd->out_pending_frames, - format->nChannels, format->nSamplesPerSec); - frames = rdpsnd->dsp_context->resampled_frames; - src = rdpsnd->dsp_context->resampled_buffer; - } - size = frames * tbytes_per_frame; - - if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM) - { - rdpsnd->dsp_context->encode_ima_adpcm(rdpsnd->dsp_context, - src, size, format->nChannels, format->nBlockAlign); - src = rdpsnd->dsp_context->adpcm_buffer; - size = rdpsnd->dsp_context->adpcm_size; - } - else if (format->wFormatTag == WAVE_FORMAT_ADPCM) - { - rdpsnd->dsp_context->encode_ms_adpcm(rdpsnd->dsp_context, - src, size, format->nChannels, format->nBlockAlign); - src = rdpsnd->dsp_context->adpcm_buffer; - size = rdpsnd->dsp_context->adpcm_size; - } - - rdpsnd->context.block_no = (rdpsnd->context.block_no + 1) % 256; - - /* Fill to nBlockAlign for the last audio packet */ - - fill_size = 0; - - if ((format->wFormatTag == WAVE_FORMAT_DVI_ADPCM || format->wFormatTag == WAVE_FORMAT_ADPCM) && - (rdpsnd->out_pending_frames < rdpsnd->out_frames) && ((size % format->nBlockAlign) != 0)) - { - fill_size = format->nBlockAlign - (size % format->nBlockAlign); - } - - /* WaveInfo PDU */ - Stream_SetPosition(s, 0); - Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */ - Stream_Write_UINT8(s, 0); /* bPad */ - Stream_Write_UINT16(s, size + fill_size + 8); /* BodySize */ - - Stream_Write_UINT16(s, 0); /* wTimeStamp */ - Stream_Write_UINT16(s, rdpsnd->context.selected_client_format); /* wFormatNo */ - Stream_Write_UINT8(s, rdpsnd->context.block_no); /* cBlockNo */ - Stream_Seek(s, 3); /* bPad */ - Stream_Write(s, src, 4); - - WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL); - Stream_SetPosition(s, 0); - - /* Wave PDU */ - Stream_EnsureRemainingCapacity(s, size + fill_size); - Stream_Write_UINT32(s, 0); /* bPad */ - Stream_Write(s, src + 4, size - 4); - - if (fill_size > 0) - Stream_Zero(s, fill_size); - - status = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL); - Stream_SetPosition(s, 0); - - rdpsnd->out_pending_frames = 0; - - return status; -} - -static BOOL rdpsnd_server_send_samples(rdpsnd_server_context* context, const void* buf, int nframes) -{ - int cframes; - int cframesize; - rdpsnd_server* rdpsnd = (rdpsnd_server*) context; - - if (rdpsnd->context.selected_client_format < 0) - return FALSE; - - while (nframes > 0) - { - cframes = MIN(nframes, rdpsnd->out_frames - rdpsnd->out_pending_frames); - cframesize = cframes * rdpsnd->src_bytes_per_frame; - - CopyMemory(rdpsnd->out_buffer + (rdpsnd->out_pending_frames * rdpsnd->src_bytes_per_frame), buf, cframesize); - buf = (BYTE*) buf + cframesize; - nframes -= cframes; - rdpsnd->out_pending_frames += cframes; - - if (rdpsnd->out_pending_frames >= rdpsnd->out_frames) - { - if (!rdpsnd_server_send_audio_pdu(rdpsnd)) - return FALSE; - } - } - - return TRUE; -} - -static BOOL rdpsnd_server_set_volume(rdpsnd_server_context* context, int left, int right) -{ - int pos; - BOOL status; - rdpsnd_server* rdpsnd = (rdpsnd_server*) context; - wStream* s = rdpsnd->rdpsnd_pdu; - - Stream_Write_UINT8(s, SNDC_SETVOLUME); - Stream_Write_UINT8(s, 0); - Stream_Seek_UINT16(s); - - Stream_Write_UINT16(s, left); - Stream_Write_UINT16(s, right); - - pos = Stream_GetPosition(s); - Stream_SetPosition(s, 2); - Stream_Write_UINT16(s, pos - 4); - Stream_SetPosition(s, pos); - status = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL); - Stream_SetPosition(s, 0); - - return status; -} - -static BOOL rdpsnd_server_close(rdpsnd_server_context* context) -{ - int pos; - BOOL status; - rdpsnd_server* rdpsnd = (rdpsnd_server*) context; - wStream* s = rdpsnd->rdpsnd_pdu; - - if (rdpsnd->context.selected_client_format < 0) - return FALSE; - - if (rdpsnd->out_pending_frames > 0) - { - if (!rdpsnd_server_send_audio_pdu(rdpsnd)) - return FALSE; - } - - rdpsnd->context.selected_client_format = -1; - - Stream_Write_UINT8(s, SNDC_CLOSE); - Stream_Write_UINT8(s, 0); - Stream_Seek_UINT16(s); - - pos = Stream_GetPosition(s); - Stream_SetPosition(s, 2); - Stream_Write_UINT16(s, pos - 4); - Stream_SetPosition(s, pos); - status = WTSVirtualChannelWrite(rdpsnd->rdpsnd_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL); - Stream_SetPosition(s, 0); - - return status; -} - -rdpsnd_server_context* rdpsnd_server_context_new(WTSVirtualChannelManager* vcm) -{ - rdpsnd_server* rdpsnd; - - rdpsnd = (rdpsnd_server*) malloc(sizeof(rdpsnd_server)); - ZeroMemory(rdpsnd, sizeof(rdpsnd_server)); - - rdpsnd->context.vcm = vcm; - rdpsnd->context.selected_client_format = -1; - rdpsnd->context.Initialize = rdpsnd_server_initialize; - rdpsnd->context.SelectFormat = rdpsnd_server_select_format; - rdpsnd->context.SendSamples = rdpsnd_server_send_samples; - rdpsnd->context.SetVolume = rdpsnd_server_set_volume; - rdpsnd->context.Close = rdpsnd_server_close; - - rdpsnd->dsp_context = freerdp_dsp_context_new(); - - return (rdpsnd_server_context*) rdpsnd; -} - -void rdpsnd_server_context_free(rdpsnd_server_context* context) -{ - rdpsnd_server* rdpsnd = (rdpsnd_server*) context; - - SetEvent(rdpsnd->StopEvent); - WaitForSingleObject(rdpsnd->thread, INFINITE); - - CloseHandle(rdpsnd->StopEvent); - CloseHandle(rdpsnd->thread); - - if (rdpsnd->rdpsnd_channel) - WTSVirtualChannelClose(rdpsnd->rdpsnd_channel); - - if (rdpsnd->rdpsnd_pdu) - Stream_Free(rdpsnd->rdpsnd_pdu, TRUE); - - if (rdpsnd->out_buffer) - free(rdpsnd->out_buffer); - - if (rdpsnd->dsp_context) - freerdp_dsp_context_free(rdpsnd->dsp_context); - - if (rdpsnd->context.client_formats) - free(rdpsnd->context.client_formats); - - free(rdpsnd); -} diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index 91d5949b9..beb589d5e 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -80,23 +80,32 @@ static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) return status; } -static void rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream* s) +static BOOL rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream* s) { UINT16 timestamp = 0; BYTE confirmBlockNum = 0; + + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + Stream_Read_UINT16(s, timestamp); Stream_Read_UINT8(s, confirmBlockNum); Stream_Seek_UINT8(s); + return TRUE; } -static void rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s) +static BOOL rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s) { UINT16 quality; + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + Stream_Read_UINT16(s, quality); Stream_Seek_UINT16(s); // reserved fprintf(stderr, "Client requested sound quality: %#0X\n", quality); + return TRUE; } static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) @@ -106,6 +115,9 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) UINT16 udpPort, version; BYTE lastblock; + if (Stream_GetRemainingLength(s) < 20) + return FALSE; + Stream_Read_UINT32(s, flags); /* dwFlags */ Stream_Read_UINT32(s, vol); /* dwVolume */ Stream_Read_UINT32(s, pitch); /* dwPitch */ @@ -115,42 +127,58 @@ static BOOL rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) Stream_Read_UINT16(s, version); /* wVersion */ Stream_Seek_UINT8(s); /* bPad */ - if (context->num_client_formats > 0) - { - context->client_formats = (AUDIO_FORMAT*) malloc(context->num_client_formats * sizeof(AUDIO_FORMAT)); - ZeroMemory(context->client_formats, sizeof(AUDIO_FORMAT)); + /* this check is only a guess as cbSize can influence the size of a format record */ + if (Stream_GetRemainingLength(s) < context->num_client_formats * 18) + return FALSE; - for (i = 0; i < context->num_client_formats; i++) - { - Stream_Read_UINT16(s, context->client_formats[i].wFormatTag); - Stream_Read_UINT16(s, context->client_formats[i].nChannels); - Stream_Read_UINT32(s, context->client_formats[i].nSamplesPerSec); - Stream_Read_UINT32(s, context->client_formats[i].nAvgBytesPerSec); - Stream_Read_UINT16(s, context->client_formats[i].nBlockAlign); - Stream_Read_UINT16(s, context->client_formats[i].wBitsPerSample); - Stream_Read_UINT16(s, context->client_formats[i].cbSize); - - if (context->client_formats[i].cbSize > 0) - { - Stream_Seek(s, context->client_formats[i].cbSize); - } - - if (context->client_formats[i].wFormatTag != 0) - { - //lets call this a known format - //TODO: actually look through our own list of known formats - num_known_format++; - } - } - } - - if (num_known_format == 0) + if (!context->num_client_formats) { - fprintf(stderr, "Client doesn't support any known formats!\n"); + fprintf(stderr, "%s: client doesn't support any format!\n", __FUNCTION__); return FALSE; } + context->client_formats = (AUDIO_FORMAT *)calloc(context->num_client_formats, sizeof(AUDIO_FORMAT)); + if (context->client_formats) + return FALSE; + + for (i = 0; i < context->num_client_formats; i++) + { + if (Stream_GetRemainingLength(s) < 18) + goto out_free; + + Stream_Read_UINT16(s, context->client_formats[i].wFormatTag); + Stream_Read_UINT16(s, context->client_formats[i].nChannels); + Stream_Read_UINT32(s, context->client_formats[i].nSamplesPerSec); + Stream_Read_UINT32(s, context->client_formats[i].nAvgBytesPerSec); + Stream_Read_UINT16(s, context->client_formats[i].nBlockAlign); + Stream_Read_UINT16(s, context->client_formats[i].wBitsPerSample); + Stream_Read_UINT16(s, context->client_formats[i].cbSize); + + if (context->client_formats[i].cbSize > 0) + { + if (!Stream_SafeSeek(s, context->client_formats[i].cbSize)) + goto out_free; + } + + if (context->client_formats[i].wFormatTag != 0) + { + //lets call this a known format + //TODO: actually look through our own list of known formats + num_known_format++; + } + } + + if (!context->num_client_formats) + { + fprintf(stderr, "%s: client doesn't support any known format!\n", __FUNCTION__); + goto out_free; + } + return TRUE; + +out_free: + free(context->client_formats); + return FALSE; } static void* rdpsnd_server_thread(void* arg) @@ -165,16 +193,19 @@ static void* rdpsnd_server_thread(void* arg) HANDLE ChannelEvent; DWORD BytesReturned; RdpsndServerContext* context; + BOOL doRun; - context = (RdpsndServerContext*) arg; + context = (RdpsndServerContext *)arg; buffer = NULL; BytesReturned = 0; ChannelEvent = NULL; s = Stream_New(NULL, 4096); + if (!s) + return NULL; - if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) + if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned)) { if (BytesReturned == sizeof(HANDLE)) CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); @@ -186,74 +217,77 @@ static void* rdpsnd_server_thread(void* arg) events[nCount++] = ChannelEvent; events[nCount++] = context->priv->StopEvent; - s = Stream_New(NULL, 4096); - rdpsnd_server_send_formats(context, s); + if (!rdpsnd_server_send_formats(context, s)) + goto out; - while (1) + doRun = TRUE; + while (doRun) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0) - { break; - } Stream_SetPosition(s, 0); - if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, - (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) + if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, + (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned)) { if (!BytesReturned) break; Stream_EnsureRemainingCapacity(s, BytesReturned); - if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, - (PCHAR) Stream_Buffer(s), Stream_Capacity(s), &BytesReturned) == FALSE) - { + if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR) Stream_Buffer(s), + Stream_Capacity(s), &BytesReturned)) break; - } } + if (Stream_GetRemainingLength(s) < 4) + break; + Stream_Read_UINT8(s, msgType); Stream_Seek_UINT8(s); /* bPad */ Stream_Read_UINT16(s, BodySize); + if (Stream_GetRemainingLength(s) < BodySize) + break; + switch (msgType) { case SNDC_WAVECONFIRM: - rdpsnd_server_recv_waveconfirm(context, s); + doRun = rdpsnd_server_recv_waveconfirm(context, s); break; case SNDC_QUALITYMODE: - rdpsnd_server_recv_quality_mode(context, s); + doRun = rdpsnd_server_recv_quality_mode(context, s); break; case SNDC_FORMATS: - if (rdpsnd_server_recv_formats(context, s)) + doRun = rdpsnd_server_recv_formats(context, s); + if (doRun) { IFCALL(context->Activated, context); } break; default: - fprintf(stderr, "UNKOWN MESSAGE TYPE!! (%#0X)\n\n", msgType); + fprintf(stderr, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, msgType); break; } } +out: Stream_Free(s, TRUE); - return NULL; } static BOOL rdpsnd_server_initialize(RdpsndServerContext* context) { - context->Start(context); - return TRUE; + return context->Start(context); } -static void rdpsnd_server_select_format(RdpsndServerContext* context, int client_format_index) +static BOOL rdpsnd_server_select_format(RdpsndServerContext* context, int client_format_index) { int bs; int out_buffer_size; @@ -261,8 +295,8 @@ static void rdpsnd_server_select_format(RdpsndServerContext* context, int client if (client_format_index < 0 || client_format_index >= context->num_client_formats) { - fprintf(stderr, "rdpsnd_server_select_format: index %d is not correct.\n", client_format_index); - return; + fprintf(stderr, "%s: index %d is not correct.\n", __FUNCTION__, client_format_index); + return FALSE; } context->priv->src_bytes_per_sample = context->src_format.wBitsPerSample / 8; @@ -273,23 +307,24 @@ static void rdpsnd_server_select_format(RdpsndServerContext* context, int client if (format->nSamplesPerSec == 0) { - fprintf(stderr, "Invalid Client Sound Format!!\n\n"); - return; + fprintf(stderr, "%s: invalid Client Sound Format!!\n", __FUNCTION__); + return FALSE; } - if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM) + switch(format->wFormatTag) { - bs = (format->nBlockAlign - 4 * format->nChannels) * 4; - context->priv->out_frames = (format->nBlockAlign * 4 * format->nChannels * 2 / bs + 1) * bs / (format->nChannels * 2); - } - else if (format->wFormatTag == WAVE_FORMAT_ADPCM) - { - bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2; - context->priv->out_frames = bs * 4; - } - else - { - context->priv->out_frames = 0x4000 / context->priv->src_bytes_per_frame; + case WAVE_FORMAT_DVI_ADPCM: + bs = (format->nBlockAlign - 4 * format->nChannels) * 4; + context->priv->out_frames = (format->nBlockAlign * 4 * format->nChannels * 2 / bs + 1) * bs / (format->nChannels * 2); + break; + + case WAVE_FORMAT_ADPCM: + bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2; + context->priv->out_frames = bs * 4; + break; + default: + context->priv->out_frames = 0x4000 / context->priv->src_bytes_per_frame; + break; } if (format->nSamplesPerSec != context->src_format.nSamplesPerSec) @@ -302,11 +337,18 @@ static void rdpsnd_server_select_format(RdpsndServerContext* context, int client if (context->priv->out_buffer_size < out_buffer_size) { - context->priv->out_buffer = (BYTE*) realloc(context->priv->out_buffer, out_buffer_size); + BYTE *newBuffer; + + newBuffer = (BYTE *)realloc(context->priv->out_buffer, out_buffer_size); + if (!newBuffer) + return FALSE; + + context->priv->out_buffer = newBuffer; context->priv->out_buffer_size = out_buffer_size; } freerdp_dsp_context_reset_adpcm(context->priv->dsp_context); + return TRUE; } static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context) @@ -379,7 +421,9 @@ static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context) Stream_Seek(s, 3); /* bPad */ Stream_Write(s, src, 4); - WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL); + if (!status) + goto out; Stream_SetPosition(s, 0); /* Wave PDU */ @@ -391,10 +435,10 @@ static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context) Stream_Zero(s, fill_size); status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL); + +out: Stream_SetPosition(s, 0); - context->priv->out_pending_frames = 0; - return status; } @@ -484,26 +528,45 @@ static BOOL rdpsnd_server_close(RdpsndServerContext* context) static int rdpsnd_server_start(RdpsndServerContext* context) { context->priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); - if (!context->priv->ChannelHandle) return -1; context->priv->rdpsnd_pdu = Stream_New(NULL, 4096); + if (!context->priv->rdpsnd_pdu) + goto out_close; context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!context->priv->StopEvent) + goto out_pdu; context->priv->Thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) rdpsnd_server_thread, (void*) context, 0, NULL); + if (!context->priv->Thread) + goto out_stopEvent; return 0; + +out_stopEvent: + CloseHandle(context->priv->StopEvent); + context->priv->StopEvent = NULL; +out_pdu: + Stream_Free(context->priv->rdpsnd_pdu, TRUE); + context->priv->rdpsnd_pdu = NULL; +out_close: + WTSVirtualChannelClose(context->priv->ChannelHandle); + context->priv->ChannelHandle = NULL; + return -1; } static int rdpsnd_server_stop(RdpsndServerContext* context) { - SetEvent(context->priv->StopEvent); + if (context->priv->StopEvent) + { + SetEvent(context->priv->StopEvent); - WaitForSingleObject(context->priv->Thread, INFINITE); - CloseHandle(context->priv->Thread); + WaitForSingleObject(context->priv->Thread, INFINITE); + CloseHandle(context->priv->Thread); + } return 0; } @@ -512,41 +575,46 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) { RdpsndServerContext* context; - context = (RdpsndServerContext*) malloc(sizeof(RdpsndServerContext)); + context = (RdpsndServerContext*) calloc(1, sizeof(RdpsndServerContext)); + if (!context) + return NULL; - if (context) - { - ZeroMemory(context, sizeof(RdpsndServerContext)); + context->vcm = vcm; - context->vcm = vcm; + context->Start = rdpsnd_server_start; + context->Stop = rdpsnd_server_stop; - context->Start = rdpsnd_server_start; - context->Stop = rdpsnd_server_stop; + context->selected_client_format = -1; + context->Initialize = rdpsnd_server_initialize; + context->SelectFormat = rdpsnd_server_select_format; + context->SendSamples = rdpsnd_server_send_samples; + context->SetVolume = rdpsnd_server_set_volume; + context->Close = rdpsnd_server_close; - context->selected_client_format = -1; - context->Initialize = rdpsnd_server_initialize; - context->SelectFormat = rdpsnd_server_select_format; - context->SendSamples = rdpsnd_server_send_samples; - context->SetVolume = rdpsnd_server_set_volume; - context->Close = rdpsnd_server_close; + context->priv = (RdpsndServerPrivate*) calloc(1, sizeof(RdpsndServerPrivate)); + if (!context->priv) + goto out_free; - context->priv = (RdpsndServerPrivate*) malloc(sizeof(RdpsndServerPrivate)); - - if (context->priv) - { - ZeroMemory(context->priv, sizeof(RdpsndServerPrivate)); - - context->priv->dsp_context = freerdp_dsp_context_new(); - } - } + context->priv->dsp_context = freerdp_dsp_context_new(); + if (!context->priv->dsp_context) + goto out_free_priv; return context; + +out_free_priv: + free(context->priv); +out_free: + free(context); + return NULL; } void rdpsnd_server_context_free(RdpsndServerContext* context) { - SetEvent(context->priv->StopEvent); - WaitForSingleObject(context->priv->Thread, INFINITE); + if (!context->priv->StopEvent) + { + SetEvent(context->priv->StopEvent); + WaitForSingleObject(context->priv->Thread, INFINITE); + } if (context->priv->ChannelHandle) WTSVirtualChannelClose(context->priv->ChannelHandle); diff --git a/include/freerdp/server/rdpsnd.h b/include/freerdp/server/rdpsnd.h index 1585389d5..e83fd231d 100644 --- a/include/freerdp/server/rdpsnd.h +++ b/include/freerdp/server/rdpsnd.h @@ -31,7 +31,7 @@ typedef int (*psRdpsndStart)(RdpsndServerContext* context); typedef int (*psRdpsndStop)(RdpsndServerContext* context); typedef BOOL (*psRdpsndServerInitialize)(RdpsndServerContext* context); -typedef void (*psRdpsndServerSelectFormat)(RdpsndServerContext* context, int client_format_index); +typedef BOOL (*psRdpsndServerSelectFormat)(RdpsndServerContext* context, int client_format_index); typedef BOOL (*psRdpsndServerSendSamples)(RdpsndServerContext* context, const void* buf, int nframes); typedef BOOL (*psRdpsndServerSetVolume)(RdpsndServerContext* context, int left, int right); typedef BOOL (*psRdpsndServerClose)(RdpsndServerContext* context); diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 734940d4e..0f0c80c66 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -652,8 +652,9 @@ FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(void) { FREERDP_DSP_CONTEXT* context; - context = (FREERDP_DSP_CONTEXT*) malloc(sizeof(FREERDP_DSP_CONTEXT)); - ZeroMemory(context, sizeof(FREERDP_DSP_CONTEXT)); + context = (FREERDP_DSP_CONTEXT*) calloc(1, sizeof(FREERDP_DSP_CONTEXT)); + if (!context) + return NULL; context->resample = freerdp_dsp_resample; context->decode_ima_adpcm = freerdp_dsp_decode_ima_adpcm;