22#include <freerdp/config.h>
29#include <winpr/assert.h>
30#include <winpr/cast.h>
31#include <winpr/print.h>
32#include <winpr/stream.h>
34#include <freerdp/freerdp.h>
35#include <freerdp/channels/log.h>
37#include "rdpsnd_common.h"
38#include "rdpsnd_main.h"
40static wStream* rdpsnd_server_get_buffer(RdpsndServerContext* context)
43 WINPR_ASSERT(context);
44 WINPR_ASSERT(context->priv);
46 s = context->priv->rdpsnd_pdu;
47 Stream_ResetPosition(s);
56static UINT rdpsnd_server_send_formats(RdpsndServerContext* context)
58 wStream* s = rdpsnd_server_get_buffer(context);
62 if (!Stream_EnsureRemainingCapacity(s, 24))
63 return ERROR_OUTOFMEMORY;
65 Stream_Write_UINT8(s, SNDC_FORMATS);
66 Stream_Write_UINT8(s, 0);
67 Stream_Seek_UINT16(s);
68 Stream_Write_UINT32(s, 0);
69 Stream_Write_UINT32(s, 0);
70 Stream_Write_UINT32(s, 0);
71 Stream_Write_UINT16(s, 0);
73 s, WINPR_ASSERTING_INT_CAST(uint16_t, context->num_server_formats));
74 Stream_Write_UINT8(s, context->block_no);
75 Stream_Write_UINT16(s, CHANNEL_VERSION_WIN_MAX);
76 Stream_Write_UINT8(s, 0);
78 for (
size_t i = 0; i < context->num_server_formats; i++)
80 const AUDIO_FORMAT* format = &context->server_formats[i];
82 if (!audio_format_write(s, format))
87 const size_t pos = Stream_GetPosition(s);
91 WINPR_ASSERT(pos >= 4);
92 if (!Stream_SetPosition(s, 2))
94 Stream_Write_UINT16(s, (UINT16)(pos - 4));
95 if (!Stream_SetPosition(s, pos))
98 WINPR_ASSERT(context->priv);
100 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
101 (UINT32)pos, &written);
102 Stream_ResetPosition(s);
105 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
113static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context,
wStream* s)
115 UINT16 timestamp = 0;
116 BYTE confirmBlockNum = 0;
117 UINT error = CHANNEL_RC_OK;
119 WINPR_ASSERT(context);
121 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
122 return ERROR_INVALID_DATA;
124 Stream_Read_UINT16(s, timestamp);
125 Stream_Read_UINT8(s, confirmBlockNum);
126 Stream_Seek_UINT8(s);
127 IFCALLRET(context->ConfirmBlock, error, context, confirmBlockNum, timestamp);
130 WLog_ERR(TAG,
"context->ConfirmBlock failed with error %" PRIu32
"", error);
140static UINT rdpsnd_server_recv_trainingconfirm(RdpsndServerContext* context,
wStream* s)
142 UINT16 timestamp = 0;
144 UINT error = CHANNEL_RC_OK;
146 WINPR_ASSERT(context);
148 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
149 return ERROR_INVALID_DATA;
151 Stream_Read_UINT16(s, timestamp);
152 Stream_Read_UINT16(s, packsize);
154 IFCALLRET(context->TrainingConfirm, error, context, timestamp, packsize);
156 WLog_ERR(TAG,
"context->TrainingConfirm failed with error %" PRIu32
"", error);
166static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context,
wStream* s)
168 WINPR_ASSERT(context);
170 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
172 WLog_ERR(TAG,
"not enough data in stream!");
173 return ERROR_INVALID_DATA;
176 Stream_Read_UINT16(s, context->qualityMode);
177 Stream_Seek_UINT16(s);
179 WLog_DBG(TAG,
"Client requested sound quality: 0x%04" PRIX16
"", context->qualityMode);
181 return CHANNEL_RC_OK;
189static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context,
wStream* s)
191 UINT error = CHANNEL_RC_OK;
193 WINPR_ASSERT(context);
195 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
196 return ERROR_INVALID_DATA;
198 Stream_Read_UINT32(s, context->capsFlags);
199 Stream_Read_UINT32(s, context->initialVolume);
200 Stream_Read_UINT32(s, context->initialPitch);
201 Stream_Read_UINT16(s, context->udpPort);
202 Stream_Read_UINT16(s, context->num_client_formats);
203 Stream_Read_UINT8(s, context->lastblock);
204 Stream_Read_UINT16(s, context->clientVersion);
205 Stream_Seek_UINT8(s);
208 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, context->num_client_formats, 18ull))
209 return ERROR_INVALID_DATA;
211 if (!context->num_client_formats)
213 WLog_ERR(TAG,
"client doesn't support any format!");
214 return ERROR_INTERNAL_ERROR;
217 context->client_formats = audio_formats_new(context->num_client_formats);
219 if (!context->client_formats)
221 WLog_ERR(TAG,
"calloc failed!");
222 return CHANNEL_RC_NO_MEMORY;
225 for (UINT16 i = 0; i < context->num_client_formats; i++)
229 if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
231 WLog_ERR(TAG,
"not enough data in stream!");
232 error = ERROR_INVALID_DATA;
236 Stream_Read_UINT16(s, format->wFormatTag);
237 Stream_Read_UINT16(s, format->nChannels);
238 Stream_Read_UINT32(s, format->nSamplesPerSec);
239 Stream_Read_UINT32(s, format->nAvgBytesPerSec);
240 Stream_Read_UINT16(s, format->nBlockAlign);
241 Stream_Read_UINT16(s, format->wBitsPerSample);
242 Stream_Read_UINT16(s, format->cbSize);
244 if (format->cbSize > 0)
246 if (!Stream_SafeSeek(s, format->cbSize))
248 WLog_ERR(TAG,
"Stream_SafeSeek failed!");
249 error = ERROR_INTERNAL_ERROR;
255 if (!context->num_client_formats)
257 WLog_ERR(TAG,
"client doesn't support any known format!");
261 return CHANNEL_RC_OK;
263 free(context->client_formats);
267static DWORD WINAPI rdpsnd_server_thread(LPVOID arg)
271 HANDLE events[2] = WINPR_C_ARRAY_INIT;
272 RdpsndServerContext* context = (RdpsndServerContext*)arg;
273 UINT error = CHANNEL_RC_OK;
275 WINPR_ASSERT(context);
276 WINPR_ASSERT(context->priv);
278 events[nCount++] = context->priv->channelEvent;
279 events[nCount++] = context->priv->StopEvent;
281 WINPR_ASSERT(nCount <= ARRAYSIZE(events));
285 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
287 if (status == WAIT_FAILED)
289 error = GetLastError();
290 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"!", error);
294 status = WaitForSingleObject(context->priv->StopEvent, 0);
296 if (status == WAIT_FAILED)
298 error = GetLastError();
299 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
303 if (status == WAIT_OBJECT_0)
306 if ((error = rdpsnd_server_handle_messages(context)))
308 WLog_ERR(TAG,
"rdpsnd_server_handle_messages failed with error %" PRIu32
"", error);
313 if (error && context->rdpcontext)
314 setChannelError(context->rdpcontext, error,
"rdpsnd_server_thread reported an error");
325static UINT rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread)
327 WINPR_ASSERT(context);
328 WINPR_ASSERT(context->priv);
330 context->priv->ownThread = ownThread;
331 return context->Start(context);
339static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 client_format_index)
342 size_t out_buffer_size = 0;
344 UINT error = CHANNEL_RC_OK;
346 WINPR_ASSERT(context);
347 WINPR_ASSERT(context->priv);
349 if ((client_format_index >= context->num_client_formats) || (!context->src_format))
351 WLog_ERR(TAG,
"index %" PRIu16
" is not correct.", client_format_index);
352 return ERROR_INVALID_DATA;
355 EnterCriticalSection(&context->priv->lock);
356 context->priv->src_bytes_per_sample = context->src_format->wBitsPerSample / 8;
357 context->priv->src_bytes_per_frame =
358 context->priv->src_bytes_per_sample * context->src_format->nChannels;
359 context->selected_client_format = client_format_index;
360 format = &context->client_formats[client_format_index];
362 if (format->nSamplesPerSec == 0)
364 WLog_ERR(TAG,
"invalid Client Sound Format!!");
365 error = ERROR_INVALID_DATA;
369 if (context->latency <= 0)
370 context->latency = 50;
372 context->priv->out_frames = context->src_format->nSamplesPerSec * context->latency / 1000;
374 if (context->priv->out_frames < 1)
375 context->priv->out_frames = 1;
377 switch (format->wFormatTag)
379 case WAVE_FORMAT_DVI_ADPCM:
380 bs = 4ULL * (format->nBlockAlign - 4ULL * format->nChannels);
381 context->priv->out_frames -= context->priv->out_frames % bs;
383 if (context->priv->out_frames < bs)
384 context->priv->out_frames = bs;
388 case WAVE_FORMAT_ADPCM:
389 bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2;
390 context->priv->out_frames -= context->priv->out_frames % bs;
392 if (context->priv->out_frames < bs)
393 context->priv->out_frames = bs;
400 context->priv->out_pending_frames = 0;
401 out_buffer_size = context->priv->out_frames * context->priv->src_bytes_per_frame;
403 if (context->priv->out_buffer_size < out_buffer_size)
405 BYTE* newBuffer =
nullptr;
406 newBuffer = (BYTE*)realloc(context->priv->out_buffer, out_buffer_size);
410 WLog_ERR(TAG,
"realloc failed!");
411 error = CHANNEL_RC_NO_MEMORY;
415 context->priv->out_buffer = newBuffer;
416 context->priv->out_buffer_size = out_buffer_size;
419 if (!freerdp_dsp_context_reset(context->priv->dsp_context, format, 0u))
420 error = ERROR_INTERNAL_ERROR;
422 LeaveCriticalSection(&context->priv->lock);
431static UINT rdpsnd_server_training(RdpsndServerContext* context, UINT16 timestamp, UINT16 packsize,
436 wStream* s = rdpsnd_server_get_buffer(context);
438 if (!Stream_EnsureRemainingCapacity(s, 8))
439 return ERROR_INTERNAL_ERROR;
441 Stream_Write_UINT8(s, SNDC_TRAINING);
442 Stream_Write_UINT8(s, 0);
443 Stream_Seek_UINT16(s);
444 Stream_Write_UINT16(s, timestamp);
445 Stream_Write_UINT16(s, packsize);
449 if (!Stream_EnsureRemainingCapacity(s, packsize))
451 Stream_ResetPosition(s);
452 return ERROR_INTERNAL_ERROR;
455 Stream_Write(s, data, packsize);
458 const size_t end = Stream_GetPosition(s);
459 if ((end < 4) || (end > UINT16_MAX))
460 return ERROR_INTERNAL_ERROR;
462 if (!Stream_SetPosition(s, 2))
463 return ERROR_INTERNAL_ERROR;
464 Stream_Write_UINT16(s, (UINT16)(end - 4));
466 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
467 (UINT32)end, &written);
469 Stream_ResetPosition(s);
471 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
474static BOOL rdpsnd_server_align_wave_pdu(
wStream* s, UINT32 alignment)
477 Stream_SealLength(s);
478 size = Stream_Length(s);
480 if ((size % alignment) != 0)
482 size_t offset = alignment - size % alignment;
484 if (!Stream_EnsureRemainingCapacity(s, offset))
487 Stream_Zero(s, offset);
490 Stream_SealLength(s);
500static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
504 UINT error = CHANNEL_RC_OK;
505 wStream* s = rdpsnd_server_get_buffer(context);
507 if (context->selected_client_format > context->num_client_formats)
508 return ERROR_INTERNAL_ERROR;
510 WINPR_ASSERT(context->client_formats);
512 format = &context->client_formats[context->selected_client_format];
514 Stream_ResetPosition(s);
516 if (!Stream_EnsureRemainingCapacity(s, 16))
517 return ERROR_OUTOFMEMORY;
519 Stream_Write_UINT8(s, SNDC_WAVE);
520 Stream_Write_UINT8(s, 0);
521 Stream_Write_UINT16(s, 0);
522 Stream_Write_UINT16(s, wTimestamp);
523 Stream_Write_UINT16(s, context->selected_client_format);
524 Stream_Write_UINT8(s, context->block_no);
526 const size_t start = Stream_GetPosition(s);
527 const BYTE* src = context->priv->out_buffer;
528 const size_t length =
529 1ull * context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
531 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s))
532 return ERROR_INTERNAL_ERROR;
535 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
536 return ERROR_INTERNAL_ERROR;
538 const size_t end = Stream_GetPosition(s);
539 const size_t pos = end - start + 8ULL;
540 if (pos > UINT16_MAX)
541 return ERROR_INTERNAL_ERROR;
542 if (!Stream_SetPosition(s, 2))
543 return ERROR_INTERNAL_ERROR;
544 Stream_Write_UINT16(s, (UINT16)pos);
545 if (!Stream_SetPosition(s, end))
546 return ERROR_INTERNAL_ERROR;
548 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
549 (UINT32)(start + 4), &written))
551 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
552 error = ERROR_INTERNAL_ERROR;
555 if (error != CHANNEL_RC_OK)
557 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
558 error = ERROR_INTERNAL_ERROR;
562 if (!Stream_SetPosition(s, start))
564 error = ERROR_INTERNAL_ERROR;
567 Stream_Write_UINT32(s, 0);
568 if (!Stream_SetPosition(s, start))
570 error = ERROR_INTERNAL_ERROR;
574 WINPR_ASSERT((end - start) <= UINT32_MAX);
575 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Pointer(s),
576 (UINT32)(end - start), &written))
578 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
579 error = ERROR_INTERNAL_ERROR;
582 context->block_no = (context->block_no + 1) % 256;
585 Stream_ResetPosition(s);
586 context->priv->out_pending_frames = 0;
596static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 formatNo,
597 const BYTE* data,
size_t size, BOOL encoded,
598 UINT16 timestamp, UINT32 audioTimeStamp)
601 UINT error = CHANNEL_RC_OK;
603 wStream* s = rdpsnd_server_get_buffer(context);
605 if (!Stream_EnsureRemainingCapacity(s, 16))
607 error = ERROR_INTERNAL_ERROR;
612 Stream_Write_UINT8(s, SNDC_WAVE2);
613 Stream_Write_UINT8(s, 0);
614 Stream_Write_UINT16(s, 0);
615 Stream_Write_UINT16(s, timestamp);
616 Stream_Write_UINT16(s, formatNo);
617 Stream_Write_UINT8(s, context->block_no);
618 Stream_Write_UINT8(s, 0);
619 Stream_Write_UINT8(s, 0);
620 Stream_Write_UINT8(s, 0);
621 Stream_Write_UINT32(s, audioTimeStamp);
625 if (!Stream_EnsureRemainingCapacity(s, size))
627 error = ERROR_INTERNAL_ERROR;
631 Stream_Write(s, data, size);
637 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, data, size, s))
639 error = ERROR_INTERNAL_ERROR;
643 format = &context->client_formats[formatNo];
644 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
646 error = ERROR_INTERNAL_ERROR;
652 const size_t end = Stream_GetPosition(s);
653 if (end > UINT16_MAX + 4)
655 error = ERROR_INTERNAL_ERROR;
659 if (!Stream_SetPosition(s, 2))
661 error = ERROR_INTERNAL_ERROR;
664 Stream_Write_UINT16(s, (UINT16)(end - 4));
666 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
667 (UINT32)end, &written);
669 if (!status || (end != written))
672 "WTSVirtualChannelWrite failed! [stream length=%" PRIuz
" - written=%" PRIu32,
674 error = ERROR_INTERNAL_ERROR;
678 context->block_no = (context->block_no + 1) % 256;
681 Stream_ResetPosition(s);
682 context->priv->out_pending_frames = 0;
687static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
689 const BYTE* src =
nullptr;
692 WINPR_ASSERT(context);
693 WINPR_ASSERT(context->priv);
695 if (context->selected_client_format >= context->num_client_formats)
696 return ERROR_INTERNAL_ERROR;
698 src = context->priv->out_buffer;
699 length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
701 if (context->clientVersion >= CHANNEL_VERSION_WIN_8)
702 return rdpsnd_server_send_wave2_pdu(context, context->selected_client_format, src, length,
703 FALSE, wTimestamp, wTimestamp);
705 return rdpsnd_server_send_wave_pdu(context, wTimestamp);
713static UINT rdpsnd_server_send_samples(RdpsndServerContext* context,
const void* buf,
714 size_t nframes, UINT16 wTimestamp)
716 UINT error = CHANNEL_RC_OK;
718 WINPR_ASSERT(context);
719 WINPR_ASSERT(context->priv);
721 EnterCriticalSection(&context->priv->lock);
723 if (context->selected_client_format >= context->num_client_formats)
726 WLog_WARN(TAG,
"Drop samples because client format has not been negotiated.");
727 error = ERROR_NOT_READY;
733 const size_t cframes =
734 MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames);
735 size_t cframesize = cframes * context->priv->src_bytes_per_frame;
736 CopyMemory(context->priv->out_buffer +
737 (context->priv->out_pending_frames * context->priv->src_bytes_per_frame),
739 buf = (
const BYTE*)buf + cframesize;
741 context->priv->out_pending_frames += cframes;
743 if (context->priv->out_pending_frames >= context->priv->out_frames)
745 if ((error = rdpsnd_server_send_audio_pdu(context, wTimestamp)))
747 WLog_ERR(TAG,
"rdpsnd_server_send_audio_pdu failed with error %" PRIu32
"", error);
754 LeaveCriticalSection(&context->priv->lock);
763static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 formatNo,
764 const void* buf,
size_t size, UINT16 timestamp,
765 UINT32 audioTimeStamp)
767 UINT error = CHANNEL_RC_OK;
769 WINPR_ASSERT(context);
770 WINPR_ASSERT(context->priv);
772 if (context->clientVersion < CHANNEL_VERSION_WIN_8)
773 return ERROR_INTERNAL_ERROR;
775 EnterCriticalSection(&context->priv->lock);
778 rdpsnd_server_send_wave2_pdu(context, formatNo, buf, size, TRUE, timestamp, audioTimeStamp);
780 LeaveCriticalSection(&context->priv->lock);
790static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, UINT16 left, UINT16 right)
794 wStream* s = rdpsnd_server_get_buffer(context);
796 if (!Stream_EnsureRemainingCapacity(s, 8))
797 return ERROR_NOT_ENOUGH_MEMORY;
799 Stream_Write_UINT8(s, SNDC_SETVOLUME);
800 Stream_Write_UINT8(s, 0);
801 Stream_Write_UINT16(s, 4);
802 Stream_Write_UINT16(s, left);
803 Stream_Write_UINT16(s, right);
805 const size_t len = Stream_GetPosition(s);
806 WINPR_ASSERT(len <= UINT32_MAX);
807 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
808 (ULONG)len, &written);
809 Stream_ResetPosition(s);
810 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
818static UINT rdpsnd_server_close(RdpsndServerContext* context)
822 UINT error = CHANNEL_RC_OK;
823 wStream* s = rdpsnd_server_get_buffer(context);
825 EnterCriticalSection(&context->priv->lock);
827 if (context->priv->out_pending_frames > 0)
829 if (context->selected_client_format >= context->num_client_formats)
831 WLog_ERR(TAG,
"Pending audio frame exists while no format selected.");
832 error = ERROR_INVALID_DATA;
834 else if ((error = rdpsnd_server_send_audio_pdu(context, 0)))
836 WLog_ERR(TAG,
"rdpsnd_server_send_audio_pdu failed with error %" PRIu32
"", error);
840 LeaveCriticalSection(&context->priv->lock);
845 context->selected_client_format = 0xFFFF;
847 if (!Stream_EnsureRemainingCapacity(s, 4))
848 return ERROR_OUTOFMEMORY;
850 Stream_Write_UINT8(s, SNDC_CLOSE);
851 Stream_Write_UINT8(s, 0);
852 Stream_Seek_UINT16(s);
853 const size_t pos = Stream_GetPosition(s);
854 WINPR_ASSERT(pos >= 4);
855 if (!Stream_SetPosition(s, 2))
856 return ERROR_INVALID_DATA;
857 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, pos - 4));
858 if (!Stream_SetPosition(s, pos))
859 return ERROR_INVALID_DATA;
861 const size_t len = Stream_GetPosition(s);
862 WINPR_ASSERT(len <= UINT32_MAX);
863 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
864 (UINT32)len, &written);
865 Stream_ResetPosition(s);
866 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
874static UINT rdpsnd_server_start(RdpsndServerContext* context)
876 void* buffer =
nullptr;
877 DWORD bytesReturned = 0;
878 RdpsndServerPrivate* priv =
nullptr;
879 UINT error = ERROR_INTERNAL_ERROR;
880 PULONG pSessionId =
nullptr;
882 WINPR_ASSERT(context);
883 WINPR_ASSERT(context->priv);
885 priv = context->priv;
886 priv->SessionId = WTS_CURRENT_SESSION;
888 if (context->use_dynamic_virtual_channel)
890 UINT32 channelId = 0;
893 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
894 (LPSTR*)&pSessionId, &bytesReturned))
896 priv->SessionId = (DWORD)*pSessionId;
897 WTSFreeMemory(pSessionId);
898 priv->ChannelHandle = WTSVirtualChannelOpenEx(priv->SessionId, RDPSND_DVC_CHANNEL_NAME,
899 WTS_CHANNEL_OPTION_DYNAMIC);
900 if (!priv->ChannelHandle)
902 WLog_ERR(TAG,
"Open audio dynamic virtual channel (%s) failed!",
903 RDPSND_DVC_CHANNEL_NAME);
904 return ERROR_INTERNAL_ERROR;
907 channelId = WTSChannelGetIdByHandle(priv->ChannelHandle);
909 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
912 WLog_ERR(TAG,
"context->ChannelIdAssigned failed!");
918 WLog_ERR(TAG,
"WTSQuerySessionInformationA failed!");
919 return ERROR_INTERNAL_ERROR;
924 priv->ChannelHandle =
925 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPSND_CHANNEL_NAME);
926 if (!priv->ChannelHandle)
928 WLog_ERR(TAG,
"Open audio static virtual channel (rdpsnd) failed!");
929 return ERROR_INTERNAL_ERROR;
933 if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
935 (bytesReturned !=
sizeof(HANDLE)))
938 "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned "
943 WTSFreeMemory(buffer);
948 priv->channelEvent = *(HANDLE*)buffer;
949 WTSFreeMemory(buffer);
950 priv->rdpsnd_pdu = Stream_New(
nullptr, 4096);
952 if (!priv->rdpsnd_pdu)
954 WLog_ERR(TAG,
"Stream_New failed!");
955 error = CHANNEL_RC_NO_MEMORY;
959 if (!InitializeCriticalSectionEx(&context->priv->lock, 0, 0))
961 WLog_ERR(TAG,
"InitializeCriticalSectionEx failed!");
965 if ((error = rdpsnd_server_send_formats(context)))
967 WLog_ERR(TAG,
"rdpsnd_server_send_formats failed with error %" PRIu32
"", error);
973 context->priv->StopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
975 if (!context->priv->StopEvent)
977 WLog_ERR(TAG,
"CreateEvent failed!");
981 context->priv->Thread =
982 CreateThread(
nullptr, 0, rdpsnd_server_thread, (
void*)context, 0,
nullptr);
984 if (!context->priv->Thread)
986 WLog_ERR(TAG,
"CreateThread failed!");
991 return CHANNEL_RC_OK;
993 (void)CloseHandle(context->priv->StopEvent);
994 context->priv->StopEvent =
nullptr;
996 DeleteCriticalSection(&context->priv->lock);
998 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
999 context->priv->rdpsnd_pdu =
nullptr;
1001 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1002 context->priv->ChannelHandle =
nullptr;
1011static UINT rdpsnd_server_stop(RdpsndServerContext* context)
1013 UINT error = CHANNEL_RC_OK;
1015 WINPR_ASSERT(context);
1016 WINPR_ASSERT(context->priv);
1018 if (!context->priv->StopEvent)
1021 if (context->priv->ownThread)
1023 if (context->priv->StopEvent)
1025 (void)SetEvent(context->priv->StopEvent);
1027 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
1029 error = GetLastError();
1030 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
1034 (void)CloseHandle(context->priv->Thread);
1035 (void)CloseHandle(context->priv->StopEvent);
1036 context->priv->Thread =
nullptr;
1037 context->priv->StopEvent =
nullptr;
1041 DeleteCriticalSection(&context->priv->lock);
1043 if (context->priv->rdpsnd_pdu)
1045 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1046 context->priv->rdpsnd_pdu =
nullptr;
1049 if (context->priv->ChannelHandle)
1051 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1052 context->priv->ChannelHandle =
nullptr;
1058RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
1060 RdpsndServerPrivate* priv =
nullptr;
1061 RdpsndServerContext* context = (RdpsndServerContext*)calloc(1,
sizeof(RdpsndServerContext));
1067 context->Start = rdpsnd_server_start;
1068 context->Stop = rdpsnd_server_stop;
1069 context->selected_client_format = 0xFFFF;
1070 context->Initialize = rdpsnd_server_initialize;
1071 context->SendFormats = rdpsnd_server_send_formats;
1072 context->SelectFormat = rdpsnd_server_select_format;
1073 context->Training = rdpsnd_server_training;
1074 context->SendSamples = rdpsnd_server_send_samples;
1075 context->SendSamples2 = rdpsnd_server_send_samples2;
1076 context->SetVolume = rdpsnd_server_set_volume;
1077 context->Close = rdpsnd_server_close;
1078 context->priv = priv = (RdpsndServerPrivate*)calloc(1,
sizeof(RdpsndServerPrivate));
1082 WLog_ERR(TAG,
"calloc failed!");
1086 priv->dsp_context = freerdp_dsp_context_new(TRUE);
1088 if (!priv->dsp_context)
1090 WLog_ERR(TAG,
"freerdp_dsp_context_new failed!");
1094 priv->input_stream = Stream_New(
nullptr, 4);
1096 if (!priv->input_stream)
1098 WLog_ERR(TAG,
"Stream_New failed!");
1102 priv->expectedBytes = 4;
1103 priv->waitingHeader = TRUE;
1104 priv->ownThread = TRUE;
1107 WINPR_PRAGMA_DIAG_PUSH
1108 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1109 rdpsnd_server_context_free(context);
1110 WINPR_PRAGMA_DIAG_POP
1114void rdpsnd_server_context_reset(RdpsndServerContext* context)
1116 WINPR_ASSERT(context);
1117 WINPR_ASSERT(context->priv);
1119 context->priv->expectedBytes = 4;
1120 context->priv->waitingHeader = TRUE;
1121 Stream_ResetPosition(context->priv->input_stream);
1124void rdpsnd_server_context_free(RdpsndServerContext* context)
1131 rdpsnd_server_stop(context);
1133 free(context->priv->out_buffer);
1135 if (context->priv->dsp_context)
1136 freerdp_dsp_context_free(context->priv->dsp_context);
1138 if (context->priv->input_stream)
1139 Stream_Free(context->priv->input_stream, TRUE);
1142 free(context->server_formats);
1143 free(context->client_formats);
1144 free(context->priv);
1148HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context)
1150 WINPR_ASSERT(context);
1151 WINPR_ASSERT(context->priv);
1153 return context->priv->channelEvent;
1170UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
1172 DWORD bytesReturned = 0;
1173 UINT ret = CHANNEL_RC_OK;
1174 RdpsndServerPrivate* priv =
nullptr;
1177 WINPR_ASSERT(context);
1178 WINPR_ASSERT(context->priv);
1180 priv = context->priv;
1181 s = priv->input_stream;
1183 if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
1186 if (GetLastError() == ERROR_NO_DATA)
1187 return ERROR_NO_DATA;
1189 WLog_ERR(TAG,
"channel connection closed");
1190 return ERROR_INTERNAL_ERROR;
1193 priv->expectedBytes -= bytesReturned;
1194 Stream_Seek(s, bytesReturned);
1196 if (priv->expectedBytes)
1197 return CHANNEL_RC_OK;
1199 Stream_SealLength(s);
1200 Stream_ResetPosition(s);
1202 if (priv->waitingHeader)
1205 Stream_Read_UINT8(s, priv->msgType);
1206 Stream_Seek_UINT8(s);
1207 Stream_Read_UINT16(s, priv->expectedBytes);
1208 priv->waitingHeader = FALSE;
1209 Stream_ResetPosition(s);
1211 if (priv->expectedBytes)
1213 if (!Stream_EnsureCapacity(s, priv->expectedBytes))
1215 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
1216 return CHANNEL_RC_NO_MEMORY;
1219 return CHANNEL_RC_OK;
1224#ifdef WITH_DEBUG_SND
1225 WLog_DBG(TAG,
"message type %" PRIu8
"", priv->msgType);
1227 priv->expectedBytes = 4;
1228 priv->waitingHeader = TRUE;
1230 switch (priv->msgType)
1232 case SNDC_WAVECONFIRM:
1233 ret = rdpsnd_server_recv_waveconfirm(context, s);
1237 ret = rdpsnd_server_recv_trainingconfirm(context, s);
1241 ret = rdpsnd_server_recv_formats(context, s);
1243 if ((ret == CHANNEL_RC_OK) && (context->clientVersion < CHANNEL_VERSION_WIN_7))
1244 IFCALL(context->Activated, context);
1248 case SNDC_QUALITYMODE:
1249 ret = rdpsnd_server_recv_quality_mode(context, s);
1251 if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7))
1252 IFCALL(context->Activated, context);
1257 WLog_ERR(TAG,
"UNKNOWN MESSAGE TYPE!! (0x%02" PRIX8
")", priv->msgType);
1258 ret = ERROR_INVALID_DATA;
1262 Stream_ResetPosition(s);