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;
184static void rdpsnd_server_client_format_free(RdpsndServerContext* context)
186 WINPR_ASSERT(context);
187 audio_formats_free(context->client_formats, context->num_client_formats);
188 context->client_formats =
nullptr;
189 context->num_client_formats = 0;
197static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context,
wStream* s)
199 UINT error = CHANNEL_RC_OK;
201 WINPR_ASSERT(context);
203 rdpsnd_server_client_format_free(context);
205 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
206 return ERROR_INVALID_DATA;
208 Stream_Read_UINT32(s, context->capsFlags);
209 Stream_Read_UINT32(s, context->initialVolume);
210 Stream_Read_UINT32(s, context->initialPitch);
211 Stream_Read_UINT16(s, context->udpPort);
212 Stream_Read_UINT16(s, context->num_client_formats);
213 Stream_Read_UINT8(s, context->lastblock);
214 Stream_Read_UINT16(s, context->clientVersion);
215 Stream_Seek_UINT8(s);
218 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, context->num_client_formats, 18ull))
219 return ERROR_INVALID_DATA;
221 if (!context->num_client_formats)
223 WLog_ERR(TAG,
"client doesn't support any format!");
224 return ERROR_INTERNAL_ERROR;
227 context->client_formats = audio_formats_new(context->num_client_formats);
229 if (!context->client_formats)
231 WLog_ERR(TAG,
"calloc failed!");
232 return CHANNEL_RC_NO_MEMORY;
235 for (UINT16 i = 0; i < context->num_client_formats; i++)
238 audio_format_free(format);
240 if (!audio_format_read(s, format))
248 if ((format->nChannels == 0) || (format->nBlockAlign == 0))
250 WLog_ERR(TAG,
"invalid client audio format: nChannels or nBlockAlign is 0");
251 error = ERROR_INVALID_DATA;
256 switch (format->wFormatTag)
258 case WAVE_FORMAT_DVI_ADPCM:
259 if (format->nBlockAlign < 4)
262 "invalid client audio format %s: nBlockAlign is %" PRIu32
264 audio_format_get_tag_string(format->wFormatTag), format->nBlockAlign);
265 error = ERROR_INVALID_DATA;
269 case WAVE_FORMAT_ADPCM:
270 if (format->nBlockAlign < 8)
273 "invalid client audio format %s: nBlockAlign is %" PRIu32
275 audio_format_get_tag_string(format->wFormatTag), format->nBlockAlign);
276 error = ERROR_INVALID_DATA;
285 if (!context->num_client_formats)
287 WLog_ERR(TAG,
"client doesn't support any known format!");
291 return CHANNEL_RC_OK;
293 rdpsnd_server_client_format_free(context);
297static DWORD WINAPI rdpsnd_server_thread(LPVOID arg)
301 HANDLE events[2] = WINPR_C_ARRAY_INIT;
302 RdpsndServerContext* context = (RdpsndServerContext*)arg;
303 UINT error = CHANNEL_RC_OK;
305 WINPR_ASSERT(context);
306 WINPR_ASSERT(context->priv);
308 events[nCount++] = context->priv->channelEvent;
309 events[nCount++] = context->priv->StopEvent;
311 WINPR_ASSERT(nCount <= ARRAYSIZE(events));
315 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
317 if (status == WAIT_FAILED)
319 error = GetLastError();
320 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"!", error);
324 status = WaitForSingleObject(context->priv->StopEvent, 0);
326 if (status == WAIT_FAILED)
328 error = GetLastError();
329 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
333 if (status == WAIT_OBJECT_0)
336 if ((error = rdpsnd_server_handle_messages(context)))
338 WLog_ERR(TAG,
"rdpsnd_server_handle_messages failed with error %" PRIu32
"", error);
343 if (error && context->rdpcontext)
344 setChannelError(context->rdpcontext, error,
"rdpsnd_server_thread reported an error");
355static UINT rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread)
357 WINPR_ASSERT(context);
358 WINPR_ASSERT(context->priv);
360 context->priv->ownThread = ownThread;
361 return context->Start(context);
369static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 client_format_index)
371 UINT error = CHANNEL_RC_OK;
373 WINPR_ASSERT(context);
374 WINPR_ASSERT(context->priv);
376 if ((client_format_index >= context->num_client_formats) || (!context->src_format))
378 WLog_ERR(TAG,
"index %" PRIu16
" is not correct.", client_format_index);
379 return ERROR_INVALID_DATA;
382 EnterCriticalSection(&context->priv->lock);
383 context->priv->src_bytes_per_sample = context->src_format->wBitsPerSample / 8;
384 context->priv->src_bytes_per_frame =
385 context->priv->src_bytes_per_sample * context->src_format->nChannels;
386 context->selected_client_format = client_format_index;
388 const AUDIO_FORMAT* format = &context->client_formats[client_format_index];
390 if (format->nSamplesPerSec == 0)
392 WLog_ERR(TAG,
"invalid Client Sound Format!!");
393 error = ERROR_INVALID_DATA;
397 if (context->latency <= 0)
398 context->latency = 50;
400 context->priv->out_frames = context->src_format->nSamplesPerSec * context->latency / 1000;
402 if (context->priv->out_frames < 1)
403 context->priv->out_frames = 1;
405 switch (format->wFormatTag)
407 case WAVE_FORMAT_DVI_ADPCM:
409 if (format->nBlockAlign / 4ull < format->nChannels)
411 if (format->nChannels == 0)
418 const size_t bs = 4ULL * (format->nBlockAlign - 4ULL * format->nChannels);
420 context->priv->out_frames -= context->priv->out_frames % bs;
422 if (context->priv->out_frames < bs)
423 context->priv->out_frames = bs;
427 case WAVE_FORMAT_ADPCM:
429 if (format->nBlockAlign / 7 < format->nChannels)
431 if (format->nChannels == 0)
440 (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2;
442 context->priv->out_frames -= context->priv->out_frames % bs;
444 if (context->priv->out_frames < bs)
445 context->priv->out_frames = bs;
452 context->priv->out_pending_frames = 0;
453 const size_t out_buffer_size = context->priv->out_frames * context->priv->src_bytes_per_frame;
455 if (context->priv->out_buffer_size < out_buffer_size)
457 BYTE* newBuffer = (BYTE*)realloc(context->priv->out_buffer, out_buffer_size);
461 WLog_ERR(TAG,
"realloc failed!");
462 error = CHANNEL_RC_NO_MEMORY;
466 context->priv->out_buffer = newBuffer;
467 context->priv->out_buffer_size = out_buffer_size;
470 if (!freerdp_dsp_context_reset(context->priv->dsp_context, format, 0u))
471 error = ERROR_INTERNAL_ERROR;
473 LeaveCriticalSection(&context->priv->lock);
482static UINT rdpsnd_server_training(RdpsndServerContext* context, UINT16 timestamp, UINT16 packsize,
487 wStream* s = rdpsnd_server_get_buffer(context);
489 if (!Stream_EnsureRemainingCapacity(s, 8))
490 return ERROR_INTERNAL_ERROR;
492 Stream_Write_UINT8(s, SNDC_TRAINING);
493 Stream_Write_UINT8(s, 0);
494 Stream_Seek_UINT16(s);
495 Stream_Write_UINT16(s, timestamp);
496 Stream_Write_UINT16(s, packsize);
500 if (!Stream_EnsureRemainingCapacity(s, packsize))
502 Stream_ResetPosition(s);
503 return ERROR_INTERNAL_ERROR;
506 Stream_Write(s, data, packsize);
509 const size_t end = Stream_GetPosition(s);
510 if ((end < 4) || (end > UINT16_MAX))
511 return ERROR_INTERNAL_ERROR;
513 if (!Stream_SetPosition(s, 2))
514 return ERROR_INTERNAL_ERROR;
515 Stream_Write_UINT16(s, (UINT16)(end - 4));
517 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
518 (UINT32)end, &written);
520 Stream_ResetPosition(s);
522 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
532 Stream_SealLength(s);
533 size = Stream_Length(s);
535 WINPR_ASSERT(format);
536 const UINT32 alignment = format->nBlockAlign;
537 if ((format->wFormatTag != WAVE_FORMAT_OPUS) && ((size % alignment) != 0))
539 size_t offset = alignment - size % alignment;
541 if (!Stream_EnsureRemainingCapacity(s, offset))
544 Stream_Zero(s, offset);
547 Stream_SealLength(s);
557static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
560 UINT error = CHANNEL_RC_OK;
561 wStream* s = rdpsnd_server_get_buffer(context);
563 if (context->selected_client_format > context->num_client_formats)
564 return ERROR_INTERNAL_ERROR;
566 WINPR_ASSERT(context->client_formats);
568 const AUDIO_FORMAT* format = &context->client_formats[context->selected_client_format];
570 Stream_ResetPosition(s);
572 if (!Stream_EnsureRemainingCapacity(s, 16))
573 return ERROR_OUTOFMEMORY;
575 Stream_Write_UINT8(s, SNDC_WAVE);
576 Stream_Write_UINT8(s, 0);
577 Stream_Write_UINT16(s, 0);
578 Stream_Write_UINT16(s, wTimestamp);
579 Stream_Write_UINT16(s, context->selected_client_format);
580 Stream_Write_UINT8(s, context->block_no);
582 const size_t start = Stream_GetPosition(s);
583 const BYTE* src = context->priv->out_buffer;
584 const size_t length =
585 1ull * context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
587 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s))
588 return ERROR_INTERNAL_ERROR;
591 if (!rdpsnd_server_align_wave_pdu(s, format))
592 return ERROR_INTERNAL_ERROR;
594 const size_t end = Stream_GetPosition(s);
595 const size_t pos = end - start + 8ULL;
596 if (pos > UINT16_MAX)
597 return ERROR_INTERNAL_ERROR;
598 if (!Stream_SetPosition(s, 2))
599 return ERROR_INTERNAL_ERROR;
600 Stream_Write_UINT16(s, (UINT16)pos);
601 if (!Stream_SetPosition(s, end))
602 return ERROR_INTERNAL_ERROR;
604 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
605 (UINT32)(start + 4), &written))
607 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
608 error = ERROR_INTERNAL_ERROR;
611 if (error != CHANNEL_RC_OK)
613 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
614 error = ERROR_INTERNAL_ERROR;
618 if (!Stream_SetPosition(s, start))
620 error = ERROR_INTERNAL_ERROR;
623 Stream_Write_UINT32(s, 0);
624 if (!Stream_SetPosition(s, start))
626 error = ERROR_INTERNAL_ERROR;
630 WINPR_ASSERT((end - start) <= UINT32_MAX);
631 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Pointer(s),
632 (UINT32)(end - start), &written))
634 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
635 error = ERROR_INTERNAL_ERROR;
638 context->block_no = (context->block_no + 1) % 256;
641 Stream_ResetPosition(s);
642 context->priv->out_pending_frames = 0;
652static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 formatNo,
653 const BYTE* data,
size_t size, BOOL encoded,
654 UINT16 timestamp, UINT32 audioTimeStamp)
657 UINT error = CHANNEL_RC_OK;
658 wStream* s = rdpsnd_server_get_buffer(context);
660 if (!Stream_EnsureRemainingCapacity(s, 16))
662 error = ERROR_INTERNAL_ERROR;
667 Stream_Write_UINT8(s, SNDC_WAVE2);
668 Stream_Write_UINT8(s, 0);
669 Stream_Write_UINT16(s, 0);
670 Stream_Write_UINT16(s, timestamp);
671 Stream_Write_UINT16(s, formatNo);
672 Stream_Write_UINT8(s, context->block_no);
673 Stream_Write_UINT8(s, 0);
674 Stream_Write_UINT8(s, 0);
675 Stream_Write_UINT8(s, 0);
676 Stream_Write_UINT32(s, audioTimeStamp);
680 if (!Stream_EnsureRemainingCapacity(s, size))
682 error = ERROR_INTERNAL_ERROR;
686 Stream_Write(s, data, size);
690 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, data, size, s))
692 error = ERROR_INTERNAL_ERROR;
696 const AUDIO_FORMAT* format = &context->client_formats[formatNo];
697 if (!rdpsnd_server_align_wave_pdu(s, format))
699 error = ERROR_INTERNAL_ERROR;
705 const size_t end = Stream_GetPosition(s);
706 if (end > UINT16_MAX + 4)
708 error = ERROR_INTERNAL_ERROR;
712 if (!Stream_SetPosition(s, 2))
714 error = ERROR_INTERNAL_ERROR;
717 Stream_Write_UINT16(s, (UINT16)(end - 4));
719 const BOOL status = WTSVirtualChannelWrite(context->priv->ChannelHandle,
720 Stream_BufferAs(s,
char), (UINT32)end, &written);
722 if (!status || (end != written))
725 "WTSVirtualChannelWrite failed! [stream length=%" PRIuz
" - written=%" PRIu32,
727 error = ERROR_INTERNAL_ERROR;
731 context->block_no = (context->block_no + 1) % 256;
734 Stream_ResetPosition(s);
735 context->priv->out_pending_frames = 0;
740static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
742 const BYTE* src =
nullptr;
745 WINPR_ASSERT(context);
746 WINPR_ASSERT(context->priv);
748 if (context->selected_client_format >= context->num_client_formats)
749 return ERROR_INTERNAL_ERROR;
751 src = context->priv->out_buffer;
752 length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
754 if (context->clientVersion >= CHANNEL_VERSION_WIN_8)
755 return rdpsnd_server_send_wave2_pdu(context, context->selected_client_format, src, length,
756 FALSE, wTimestamp, wTimestamp);
758 return rdpsnd_server_send_wave_pdu(context, wTimestamp);
766static UINT rdpsnd_server_send_samples(RdpsndServerContext* context,
const void* buf,
767 size_t nframes, UINT16 wTimestamp)
769 UINT error = CHANNEL_RC_OK;
771 WINPR_ASSERT(context);
772 WINPR_ASSERT(context->priv);
774 EnterCriticalSection(&context->priv->lock);
776 if (context->selected_client_format >= context->num_client_formats)
779 WLog_WARN(TAG,
"Drop samples because client format has not been negotiated.");
780 error = ERROR_NOT_READY;
786 const size_t cframes =
787 MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames);
788 size_t cframesize = cframes * context->priv->src_bytes_per_frame;
789 CopyMemory(context->priv->out_buffer +
790 (context->priv->out_pending_frames * context->priv->src_bytes_per_frame),
792 buf = (
const BYTE*)buf + cframesize;
794 context->priv->out_pending_frames += cframes;
796 if (context->priv->out_pending_frames >= context->priv->out_frames)
798 if ((error = rdpsnd_server_send_audio_pdu(context, wTimestamp)))
800 WLog_ERR(TAG,
"rdpsnd_server_send_audio_pdu failed with error %" PRIu32
"", error);
807 LeaveCriticalSection(&context->priv->lock);
816static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 formatNo,
817 const void* buf,
size_t size, UINT16 timestamp,
818 UINT32 audioTimeStamp)
820 UINT error = CHANNEL_RC_OK;
822 WINPR_ASSERT(context);
823 WINPR_ASSERT(context->priv);
825 if (context->clientVersion < CHANNEL_VERSION_WIN_8)
826 return ERROR_INTERNAL_ERROR;
828 EnterCriticalSection(&context->priv->lock);
831 rdpsnd_server_send_wave2_pdu(context, formatNo, buf, size, TRUE, timestamp, audioTimeStamp);
833 LeaveCriticalSection(&context->priv->lock);
843static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, UINT16 left, UINT16 right)
847 wStream* s = rdpsnd_server_get_buffer(context);
849 if (!Stream_EnsureRemainingCapacity(s, 8))
850 return ERROR_NOT_ENOUGH_MEMORY;
852 Stream_Write_UINT8(s, SNDC_SETVOLUME);
853 Stream_Write_UINT8(s, 0);
854 Stream_Write_UINT16(s, 4);
855 Stream_Write_UINT16(s, left);
856 Stream_Write_UINT16(s, right);
858 const size_t len = Stream_GetPosition(s);
859 WINPR_ASSERT(len <= UINT32_MAX);
860 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
861 (ULONG)len, &written);
862 Stream_ResetPosition(s);
863 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
871static UINT rdpsnd_server_close(RdpsndServerContext* context)
875 UINT error = CHANNEL_RC_OK;
876 wStream* s = rdpsnd_server_get_buffer(context);
878 EnterCriticalSection(&context->priv->lock);
880 if (context->priv->out_pending_frames > 0)
882 if (context->selected_client_format >= context->num_client_formats)
884 WLog_ERR(TAG,
"Pending audio frame exists while no format selected.");
885 error = ERROR_INVALID_DATA;
887 else if ((error = rdpsnd_server_send_audio_pdu(context, 0)))
889 WLog_ERR(TAG,
"rdpsnd_server_send_audio_pdu failed with error %" PRIu32
"", error);
893 LeaveCriticalSection(&context->priv->lock);
898 context->selected_client_format = 0xFFFF;
900 if (!Stream_EnsureRemainingCapacity(s, 4))
901 return ERROR_OUTOFMEMORY;
903 Stream_Write_UINT8(s, SNDC_CLOSE);
904 Stream_Write_UINT8(s, 0);
905 Stream_Seek_UINT16(s);
906 const size_t pos = Stream_GetPosition(s);
907 WINPR_ASSERT(pos >= 4);
908 if (!Stream_SetPosition(s, 2))
909 return ERROR_INVALID_DATA;
910 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, pos - 4));
911 if (!Stream_SetPosition(s, pos))
912 return ERROR_INVALID_DATA;
914 const size_t len = Stream_GetPosition(s);
915 WINPR_ASSERT(len <= UINT32_MAX);
916 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
917 (UINT32)len, &written);
918 Stream_ResetPosition(s);
919 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
927static UINT rdpsnd_server_start(RdpsndServerContext* context)
929 void* buffer =
nullptr;
930 DWORD bytesReturned = 0;
931 RdpsndServerPrivate* priv =
nullptr;
932 UINT error = ERROR_INTERNAL_ERROR;
933 PULONG pSessionId =
nullptr;
935 WINPR_ASSERT(context);
936 WINPR_ASSERT(context->priv);
938 priv = context->priv;
939 priv->SessionId = WTS_CURRENT_SESSION;
941 if (context->use_dynamic_virtual_channel)
943 UINT32 channelId = 0;
946 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
947 (LPSTR*)&pSessionId, &bytesReturned))
949 priv->SessionId = (DWORD)*pSessionId;
950 WTSFreeMemory(pSessionId);
951 priv->ChannelHandle = WTSVirtualChannelOpenEx(priv->SessionId, RDPSND_DVC_CHANNEL_NAME,
952 WTS_CHANNEL_OPTION_DYNAMIC);
953 if (!priv->ChannelHandle)
955 WLog_ERR(TAG,
"Open audio dynamic virtual channel (%s) failed!",
956 RDPSND_DVC_CHANNEL_NAME);
957 return ERROR_INTERNAL_ERROR;
960 channelId = WTSChannelGetIdByHandle(priv->ChannelHandle);
962 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
965 WLog_ERR(TAG,
"context->ChannelIdAssigned failed!");
971 WLog_ERR(TAG,
"WTSQuerySessionInformationA failed!");
972 return ERROR_INTERNAL_ERROR;
977 priv->ChannelHandle =
978 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPSND_CHANNEL_NAME);
979 if (!priv->ChannelHandle)
981 WLog_ERR(TAG,
"Open audio static virtual channel (rdpsnd) failed!");
982 return ERROR_INTERNAL_ERROR;
986 if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
988 (bytesReturned !=
sizeof(HANDLE)))
991 "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned "
996 WTSFreeMemory(buffer);
1001 priv->channelEvent = *(HANDLE*)buffer;
1002 WTSFreeMemory(buffer);
1003 priv->rdpsnd_pdu = Stream_New(
nullptr, 4096);
1005 if (!priv->rdpsnd_pdu)
1007 WLog_ERR(TAG,
"Stream_New failed!");
1008 error = CHANNEL_RC_NO_MEMORY;
1012 if (!InitializeCriticalSectionEx(&context->priv->lock, 0, 0))
1014 WLog_ERR(TAG,
"InitializeCriticalSectionEx failed!");
1018 if ((error = rdpsnd_server_send_formats(context)))
1020 WLog_ERR(TAG,
"rdpsnd_server_send_formats failed with error %" PRIu32
"", error);
1024 if (priv->ownThread)
1026 context->priv->StopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
1028 if (!context->priv->StopEvent)
1030 WLog_ERR(TAG,
"CreateEvent failed!");
1034 context->priv->Thread =
1035 CreateThread(
nullptr, 0, rdpsnd_server_thread, (
void*)context, 0,
nullptr);
1037 if (!context->priv->Thread)
1039 WLog_ERR(TAG,
"CreateThread failed!");
1044 return CHANNEL_RC_OK;
1046 (void)CloseHandle(context->priv->StopEvent);
1047 context->priv->StopEvent =
nullptr;
1049 DeleteCriticalSection(&context->priv->lock);
1051 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1052 context->priv->rdpsnd_pdu =
nullptr;
1054 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1055 context->priv->ChannelHandle =
nullptr;
1064static UINT rdpsnd_server_stop(RdpsndServerContext* context)
1066 UINT error = CHANNEL_RC_OK;
1068 WINPR_ASSERT(context);
1069 WINPR_ASSERT(context->priv);
1071 if (!context->priv->ChannelHandle)
1074 if (context->priv->ownThread)
1076 if (context->priv->StopEvent)
1078 (void)SetEvent(context->priv->StopEvent);
1080 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
1082 error = GetLastError();
1083 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
1087 (void)CloseHandle(context->priv->Thread);
1088 (void)CloseHandle(context->priv->StopEvent);
1089 context->priv->Thread =
nullptr;
1090 context->priv->StopEvent =
nullptr;
1094 DeleteCriticalSection(&context->priv->lock);
1096 if (context->priv->rdpsnd_pdu)
1098 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1099 context->priv->rdpsnd_pdu =
nullptr;
1102 if (context->priv->ChannelHandle)
1104 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1105 context->priv->ChannelHandle =
nullptr;
1111RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
1113 RdpsndServerPrivate* priv =
nullptr;
1114 RdpsndServerContext* context = (RdpsndServerContext*)calloc(1,
sizeof(RdpsndServerContext));
1120 context->Start = rdpsnd_server_start;
1121 context->Stop = rdpsnd_server_stop;
1122 context->selected_client_format = 0xFFFF;
1123 context->Initialize = rdpsnd_server_initialize;
1124 context->SendFormats = rdpsnd_server_send_formats;
1125 context->SelectFormat = rdpsnd_server_select_format;
1126 context->Training = rdpsnd_server_training;
1127 context->SendSamples = rdpsnd_server_send_samples;
1128 context->SendSamples2 = rdpsnd_server_send_samples2;
1129 context->SetVolume = rdpsnd_server_set_volume;
1130 context->Close = rdpsnd_server_close;
1131 context->priv = priv = (RdpsndServerPrivate*)calloc(1,
sizeof(RdpsndServerPrivate));
1135 WLog_ERR(TAG,
"calloc failed!");
1139 priv->dsp_context = freerdp_dsp_context_new(TRUE);
1141 if (!priv->dsp_context)
1143 WLog_ERR(TAG,
"freerdp_dsp_context_new failed!");
1147 priv->input_stream = Stream_New(
nullptr, 4);
1149 if (!priv->input_stream)
1151 WLog_ERR(TAG,
"Stream_New failed!");
1155 priv->expectedBytes = 4;
1156 priv->waitingHeader = TRUE;
1157 priv->ownThread = TRUE;
1160 WINPR_PRAGMA_DIAG_PUSH
1161 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1162 rdpsnd_server_context_free(context);
1163 WINPR_PRAGMA_DIAG_POP
1167void rdpsnd_server_context_reset(RdpsndServerContext* context)
1169 WINPR_ASSERT(context);
1170 WINPR_ASSERT(context->priv);
1172 context->priv->expectedBytes = 4;
1173 context->priv->waitingHeader = TRUE;
1174 Stream_ResetPosition(context->priv->input_stream);
1177void rdpsnd_server_context_free(RdpsndServerContext* context)
1184 rdpsnd_server_stop(context);
1186 free(context->priv->out_buffer);
1188 if (context->priv->dsp_context)
1189 freerdp_dsp_context_free(context->priv->dsp_context);
1191 if (context->priv->input_stream)
1192 Stream_Free(context->priv->input_stream, TRUE);
1195 free(context->server_formats);
1196 rdpsnd_server_client_format_free(context);
1197 free(context->priv);
1201HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context)
1203 WINPR_ASSERT(context);
1204 WINPR_ASSERT(context->priv);
1206 return context->priv->channelEvent;
1223UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
1225 DWORD bytesReturned = 0;
1226 UINT ret = CHANNEL_RC_OK;
1227 RdpsndServerPrivate* priv =
nullptr;
1230 WINPR_ASSERT(context);
1231 WINPR_ASSERT(context->priv);
1233 priv = context->priv;
1234 s = priv->input_stream;
1236 if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
1239 if (GetLastError() == ERROR_NO_DATA)
1240 return ERROR_NO_DATA;
1242 WLog_ERR(TAG,
"channel connection closed");
1243 return ERROR_INTERNAL_ERROR;
1246 priv->expectedBytes -= bytesReturned;
1247 Stream_Seek(s, bytesReturned);
1249 if (priv->expectedBytes)
1250 return CHANNEL_RC_OK;
1252 Stream_SealLength(s);
1253 Stream_ResetPosition(s);
1255 if (priv->waitingHeader)
1258 Stream_Read_UINT8(s, priv->msgType);
1259 Stream_Seek_UINT8(s);
1260 Stream_Read_UINT16(s, priv->expectedBytes);
1261 priv->waitingHeader = FALSE;
1262 Stream_ResetPosition(s);
1264 if (priv->expectedBytes)
1266 if (!Stream_EnsureCapacity(s, priv->expectedBytes))
1268 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
1269 return CHANNEL_RC_NO_MEMORY;
1272 return CHANNEL_RC_OK;
1277#ifdef WITH_DEBUG_SND
1278 WLog_DBG(TAG,
"message type %" PRIu8
"", priv->msgType);
1280 priv->expectedBytes = 4;
1281 priv->waitingHeader = TRUE;
1283 switch (priv->msgType)
1285 case SNDC_WAVECONFIRM:
1286 ret = rdpsnd_server_recv_waveconfirm(context, s);
1290 ret = rdpsnd_server_recv_trainingconfirm(context, s);
1294 ret = rdpsnd_server_recv_formats(context, s);
1296 if ((ret == CHANNEL_RC_OK) && (context->clientVersion < CHANNEL_VERSION_WIN_7))
1297 IFCALL(context->Activated, context);
1301 case SNDC_QUALITYMODE:
1302 ret = rdpsnd_server_recv_quality_mode(context, s);
1304 if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7))
1305 IFCALL(context->Activated, context);
1310 WLog_ERR(TAG,
"UNKNOWN MESSAGE TYPE!! (0x%02" PRIX8
")", priv->msgType);
1311 ret = ERROR_INVALID_DATA;
1315 Stream_ResetPosition(s);