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);
249 if ((format->nChannels == 0) || (format->nBlockAlign == 0))
251 WLog_ERR(TAG,
"invalid client audio format: nChannels or nBlockAlign is 0");
252 error = ERROR_INVALID_DATA;
256 if (format->cbSize > 0)
258 if (!Stream_SafeSeek(s, format->cbSize))
260 WLog_ERR(TAG,
"Stream_SafeSeek failed!");
261 error = ERROR_INTERNAL_ERROR;
267 if (!context->num_client_formats)
269 WLog_ERR(TAG,
"client doesn't support any known format!");
273 return CHANNEL_RC_OK;
275 free(context->client_formats);
279static DWORD WINAPI rdpsnd_server_thread(LPVOID arg)
283 HANDLE events[2] = WINPR_C_ARRAY_INIT;
284 RdpsndServerContext* context = (RdpsndServerContext*)arg;
285 UINT error = CHANNEL_RC_OK;
287 WINPR_ASSERT(context);
288 WINPR_ASSERT(context->priv);
290 events[nCount++] = context->priv->channelEvent;
291 events[nCount++] = context->priv->StopEvent;
293 WINPR_ASSERT(nCount <= ARRAYSIZE(events));
297 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
299 if (status == WAIT_FAILED)
301 error = GetLastError();
302 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"!", error);
306 status = WaitForSingleObject(context->priv->StopEvent, 0);
308 if (status == WAIT_FAILED)
310 error = GetLastError();
311 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
315 if (status == WAIT_OBJECT_0)
318 if ((error = rdpsnd_server_handle_messages(context)))
320 WLog_ERR(TAG,
"rdpsnd_server_handle_messages failed with error %" PRIu32
"", error);
325 if (error && context->rdpcontext)
326 setChannelError(context->rdpcontext, error,
"rdpsnd_server_thread reported an error");
337static UINT rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread)
339 WINPR_ASSERT(context);
340 WINPR_ASSERT(context->priv);
342 context->priv->ownThread = ownThread;
343 return context->Start(context);
351static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 client_format_index)
354 size_t out_buffer_size = 0;
356 UINT error = CHANNEL_RC_OK;
358 WINPR_ASSERT(context);
359 WINPR_ASSERT(context->priv);
361 if ((client_format_index >= context->num_client_formats) || (!context->src_format))
363 WLog_ERR(TAG,
"index %" PRIu16
" is not correct.", client_format_index);
364 return ERROR_INVALID_DATA;
367 EnterCriticalSection(&context->priv->lock);
368 context->priv->src_bytes_per_sample = context->src_format->wBitsPerSample / 8;
369 context->priv->src_bytes_per_frame =
370 context->priv->src_bytes_per_sample * context->src_format->nChannels;
371 context->selected_client_format = client_format_index;
372 format = &context->client_formats[client_format_index];
374 if (format->nSamplesPerSec == 0)
376 WLog_ERR(TAG,
"invalid Client Sound Format!!");
377 error = ERROR_INVALID_DATA;
381 if (context->latency <= 0)
382 context->latency = 50;
384 context->priv->out_frames = context->src_format->nSamplesPerSec * context->latency / 1000;
386 if (context->priv->out_frames < 1)
387 context->priv->out_frames = 1;
389 switch (format->wFormatTag)
391 case WAVE_FORMAT_DVI_ADPCM:
392 bs = 4ULL * (format->nBlockAlign - 4ULL * format->nChannels);
393 context->priv->out_frames -= context->priv->out_frames % bs;
395 if (context->priv->out_frames < bs)
396 context->priv->out_frames = bs;
400 case WAVE_FORMAT_ADPCM:
401 bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2;
402 context->priv->out_frames -= context->priv->out_frames % bs;
404 if (context->priv->out_frames < bs)
405 context->priv->out_frames = bs;
412 context->priv->out_pending_frames = 0;
413 out_buffer_size = context->priv->out_frames * context->priv->src_bytes_per_frame;
415 if (context->priv->out_buffer_size < out_buffer_size)
417 BYTE* newBuffer =
nullptr;
418 newBuffer = (BYTE*)realloc(context->priv->out_buffer, out_buffer_size);
422 WLog_ERR(TAG,
"realloc failed!");
423 error = CHANNEL_RC_NO_MEMORY;
427 context->priv->out_buffer = newBuffer;
428 context->priv->out_buffer_size = out_buffer_size;
431 if (!freerdp_dsp_context_reset(context->priv->dsp_context, format, 0u))
432 error = ERROR_INTERNAL_ERROR;
434 LeaveCriticalSection(&context->priv->lock);
443static UINT rdpsnd_server_training(RdpsndServerContext* context, UINT16 timestamp, UINT16 packsize,
448 wStream* s = rdpsnd_server_get_buffer(context);
450 if (!Stream_EnsureRemainingCapacity(s, 8))
451 return ERROR_INTERNAL_ERROR;
453 Stream_Write_UINT8(s, SNDC_TRAINING);
454 Stream_Write_UINT8(s, 0);
455 Stream_Seek_UINT16(s);
456 Stream_Write_UINT16(s, timestamp);
457 Stream_Write_UINT16(s, packsize);
461 if (!Stream_EnsureRemainingCapacity(s, packsize))
463 Stream_ResetPosition(s);
464 return ERROR_INTERNAL_ERROR;
467 Stream_Write(s, data, packsize);
470 const size_t end = Stream_GetPosition(s);
471 if ((end < 4) || (end > UINT16_MAX))
472 return ERROR_INTERNAL_ERROR;
474 if (!Stream_SetPosition(s, 2))
475 return ERROR_INTERNAL_ERROR;
476 Stream_Write_UINT16(s, (UINT16)(end - 4));
478 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
479 (UINT32)end, &written);
481 Stream_ResetPosition(s);
483 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
486static BOOL rdpsnd_server_align_wave_pdu(
wStream* s, UINT32 alignment)
489 Stream_SealLength(s);
490 size = Stream_Length(s);
492 if ((size % alignment) != 0)
494 size_t offset = alignment - size % alignment;
496 if (!Stream_EnsureRemainingCapacity(s, offset))
499 Stream_Zero(s, offset);
502 Stream_SealLength(s);
512static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
516 UINT error = CHANNEL_RC_OK;
517 wStream* s = rdpsnd_server_get_buffer(context);
519 if (context->selected_client_format > context->num_client_formats)
520 return ERROR_INTERNAL_ERROR;
522 WINPR_ASSERT(context->client_formats);
524 format = &context->client_formats[context->selected_client_format];
526 Stream_ResetPosition(s);
528 if (!Stream_EnsureRemainingCapacity(s, 16))
529 return ERROR_OUTOFMEMORY;
531 Stream_Write_UINT8(s, SNDC_WAVE);
532 Stream_Write_UINT8(s, 0);
533 Stream_Write_UINT16(s, 0);
534 Stream_Write_UINT16(s, wTimestamp);
535 Stream_Write_UINT16(s, context->selected_client_format);
536 Stream_Write_UINT8(s, context->block_no);
538 const size_t start = Stream_GetPosition(s);
539 const BYTE* src = context->priv->out_buffer;
540 const size_t length =
541 1ull * context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
543 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s))
544 return ERROR_INTERNAL_ERROR;
547 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
548 return ERROR_INTERNAL_ERROR;
550 const size_t end = Stream_GetPosition(s);
551 const size_t pos = end - start + 8ULL;
552 if (pos > UINT16_MAX)
553 return ERROR_INTERNAL_ERROR;
554 if (!Stream_SetPosition(s, 2))
555 return ERROR_INTERNAL_ERROR;
556 Stream_Write_UINT16(s, (UINT16)pos);
557 if (!Stream_SetPosition(s, end))
558 return ERROR_INTERNAL_ERROR;
560 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
561 (UINT32)(start + 4), &written))
563 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
564 error = ERROR_INTERNAL_ERROR;
567 if (error != CHANNEL_RC_OK)
569 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
570 error = ERROR_INTERNAL_ERROR;
574 if (!Stream_SetPosition(s, start))
576 error = ERROR_INTERNAL_ERROR;
579 Stream_Write_UINT32(s, 0);
580 if (!Stream_SetPosition(s, start))
582 error = ERROR_INTERNAL_ERROR;
586 WINPR_ASSERT((end - start) <= UINT32_MAX);
587 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Pointer(s),
588 (UINT32)(end - start), &written))
590 WLog_ERR(TAG,
"WTSVirtualChannelWrite failed!");
591 error = ERROR_INTERNAL_ERROR;
594 context->block_no = (context->block_no + 1) % 256;
597 Stream_ResetPosition(s);
598 context->priv->out_pending_frames = 0;
608static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 formatNo,
609 const BYTE* data,
size_t size, BOOL encoded,
610 UINT16 timestamp, UINT32 audioTimeStamp)
613 UINT error = CHANNEL_RC_OK;
615 wStream* s = rdpsnd_server_get_buffer(context);
617 if (!Stream_EnsureRemainingCapacity(s, 16))
619 error = ERROR_INTERNAL_ERROR;
624 Stream_Write_UINT8(s, SNDC_WAVE2);
625 Stream_Write_UINT8(s, 0);
626 Stream_Write_UINT16(s, 0);
627 Stream_Write_UINT16(s, timestamp);
628 Stream_Write_UINT16(s, formatNo);
629 Stream_Write_UINT8(s, context->block_no);
630 Stream_Write_UINT8(s, 0);
631 Stream_Write_UINT8(s, 0);
632 Stream_Write_UINT8(s, 0);
633 Stream_Write_UINT32(s, audioTimeStamp);
637 if (!Stream_EnsureRemainingCapacity(s, size))
639 error = ERROR_INTERNAL_ERROR;
643 Stream_Write(s, data, size);
649 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, data, size, s))
651 error = ERROR_INTERNAL_ERROR;
655 format = &context->client_formats[formatNo];
656 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
658 error = ERROR_INTERNAL_ERROR;
664 const size_t end = Stream_GetPosition(s);
665 if (end > UINT16_MAX + 4)
667 error = ERROR_INTERNAL_ERROR;
671 if (!Stream_SetPosition(s, 2))
673 error = ERROR_INTERNAL_ERROR;
676 Stream_Write_UINT16(s, (UINT16)(end - 4));
678 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
679 (UINT32)end, &written);
681 if (!status || (end != written))
684 "WTSVirtualChannelWrite failed! [stream length=%" PRIuz
" - written=%" PRIu32,
686 error = ERROR_INTERNAL_ERROR;
690 context->block_no = (context->block_no + 1) % 256;
693 Stream_ResetPosition(s);
694 context->priv->out_pending_frames = 0;
699static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
701 const BYTE* src =
nullptr;
704 WINPR_ASSERT(context);
705 WINPR_ASSERT(context->priv);
707 if (context->selected_client_format >= context->num_client_formats)
708 return ERROR_INTERNAL_ERROR;
710 src = context->priv->out_buffer;
711 length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
713 if (context->clientVersion >= CHANNEL_VERSION_WIN_8)
714 return rdpsnd_server_send_wave2_pdu(context, context->selected_client_format, src, length,
715 FALSE, wTimestamp, wTimestamp);
717 return rdpsnd_server_send_wave_pdu(context, wTimestamp);
725static UINT rdpsnd_server_send_samples(RdpsndServerContext* context,
const void* buf,
726 size_t nframes, UINT16 wTimestamp)
728 UINT error = CHANNEL_RC_OK;
730 WINPR_ASSERT(context);
731 WINPR_ASSERT(context->priv);
733 EnterCriticalSection(&context->priv->lock);
735 if (context->selected_client_format >= context->num_client_formats)
738 WLog_WARN(TAG,
"Drop samples because client format has not been negotiated.");
739 error = ERROR_NOT_READY;
745 const size_t cframes =
746 MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames);
747 size_t cframesize = cframes * context->priv->src_bytes_per_frame;
748 CopyMemory(context->priv->out_buffer +
749 (context->priv->out_pending_frames * context->priv->src_bytes_per_frame),
751 buf = (
const BYTE*)buf + cframesize;
753 context->priv->out_pending_frames += cframes;
755 if (context->priv->out_pending_frames >= context->priv->out_frames)
757 if ((error = rdpsnd_server_send_audio_pdu(context, wTimestamp)))
759 WLog_ERR(TAG,
"rdpsnd_server_send_audio_pdu failed with error %" PRIu32
"", error);
766 LeaveCriticalSection(&context->priv->lock);
775static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 formatNo,
776 const void* buf,
size_t size, UINT16 timestamp,
777 UINT32 audioTimeStamp)
779 UINT error = CHANNEL_RC_OK;
781 WINPR_ASSERT(context);
782 WINPR_ASSERT(context->priv);
784 if (context->clientVersion < CHANNEL_VERSION_WIN_8)
785 return ERROR_INTERNAL_ERROR;
787 EnterCriticalSection(&context->priv->lock);
790 rdpsnd_server_send_wave2_pdu(context, formatNo, buf, size, TRUE, timestamp, audioTimeStamp);
792 LeaveCriticalSection(&context->priv->lock);
802static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, UINT16 left, UINT16 right)
806 wStream* s = rdpsnd_server_get_buffer(context);
808 if (!Stream_EnsureRemainingCapacity(s, 8))
809 return ERROR_NOT_ENOUGH_MEMORY;
811 Stream_Write_UINT8(s, SNDC_SETVOLUME);
812 Stream_Write_UINT8(s, 0);
813 Stream_Write_UINT16(s, 4);
814 Stream_Write_UINT16(s, left);
815 Stream_Write_UINT16(s, right);
817 const size_t len = Stream_GetPosition(s);
818 WINPR_ASSERT(len <= UINT32_MAX);
819 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
820 (ULONG)len, &written);
821 Stream_ResetPosition(s);
822 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
830static UINT rdpsnd_server_close(RdpsndServerContext* context)
834 UINT error = CHANNEL_RC_OK;
835 wStream* s = rdpsnd_server_get_buffer(context);
837 EnterCriticalSection(&context->priv->lock);
839 if (context->priv->out_pending_frames > 0)
841 if (context->selected_client_format >= context->num_client_formats)
843 WLog_ERR(TAG,
"Pending audio frame exists while no format selected.");
844 error = ERROR_INVALID_DATA;
846 else if ((error = rdpsnd_server_send_audio_pdu(context, 0)))
848 WLog_ERR(TAG,
"rdpsnd_server_send_audio_pdu failed with error %" PRIu32
"", error);
852 LeaveCriticalSection(&context->priv->lock);
857 context->selected_client_format = 0xFFFF;
859 if (!Stream_EnsureRemainingCapacity(s, 4))
860 return ERROR_OUTOFMEMORY;
862 Stream_Write_UINT8(s, SNDC_CLOSE);
863 Stream_Write_UINT8(s, 0);
864 Stream_Seek_UINT16(s);
865 const size_t pos = Stream_GetPosition(s);
866 WINPR_ASSERT(pos >= 4);
867 if (!Stream_SetPosition(s, 2))
868 return ERROR_INVALID_DATA;
869 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, pos - 4));
870 if (!Stream_SetPosition(s, pos))
871 return ERROR_INVALID_DATA;
873 const size_t len = Stream_GetPosition(s);
874 WINPR_ASSERT(len <= UINT32_MAX);
875 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s,
char),
876 (UINT32)len, &written);
877 Stream_ResetPosition(s);
878 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
886static UINT rdpsnd_server_start(RdpsndServerContext* context)
888 void* buffer =
nullptr;
889 DWORD bytesReturned = 0;
890 RdpsndServerPrivate* priv =
nullptr;
891 UINT error = ERROR_INTERNAL_ERROR;
892 PULONG pSessionId =
nullptr;
894 WINPR_ASSERT(context);
895 WINPR_ASSERT(context->priv);
897 priv = context->priv;
898 priv->SessionId = WTS_CURRENT_SESSION;
900 if (context->use_dynamic_virtual_channel)
902 UINT32 channelId = 0;
905 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
906 (LPSTR*)&pSessionId, &bytesReturned))
908 priv->SessionId = (DWORD)*pSessionId;
909 WTSFreeMemory(pSessionId);
910 priv->ChannelHandle = WTSVirtualChannelOpenEx(priv->SessionId, RDPSND_DVC_CHANNEL_NAME,
911 WTS_CHANNEL_OPTION_DYNAMIC);
912 if (!priv->ChannelHandle)
914 WLog_ERR(TAG,
"Open audio dynamic virtual channel (%s) failed!",
915 RDPSND_DVC_CHANNEL_NAME);
916 return ERROR_INTERNAL_ERROR;
919 channelId = WTSChannelGetIdByHandle(priv->ChannelHandle);
921 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
924 WLog_ERR(TAG,
"context->ChannelIdAssigned failed!");
930 WLog_ERR(TAG,
"WTSQuerySessionInformationA failed!");
931 return ERROR_INTERNAL_ERROR;
936 priv->ChannelHandle =
937 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPSND_CHANNEL_NAME);
938 if (!priv->ChannelHandle)
940 WLog_ERR(TAG,
"Open audio static virtual channel (rdpsnd) failed!");
941 return ERROR_INTERNAL_ERROR;
945 if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
947 (bytesReturned !=
sizeof(HANDLE)))
950 "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned "
955 WTSFreeMemory(buffer);
960 priv->channelEvent = *(HANDLE*)buffer;
961 WTSFreeMemory(buffer);
962 priv->rdpsnd_pdu = Stream_New(
nullptr, 4096);
964 if (!priv->rdpsnd_pdu)
966 WLog_ERR(TAG,
"Stream_New failed!");
967 error = CHANNEL_RC_NO_MEMORY;
971 if (!InitializeCriticalSectionEx(&context->priv->lock, 0, 0))
973 WLog_ERR(TAG,
"InitializeCriticalSectionEx failed!");
977 if ((error = rdpsnd_server_send_formats(context)))
979 WLog_ERR(TAG,
"rdpsnd_server_send_formats failed with error %" PRIu32
"", error);
985 context->priv->StopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
987 if (!context->priv->StopEvent)
989 WLog_ERR(TAG,
"CreateEvent failed!");
993 context->priv->Thread =
994 CreateThread(
nullptr, 0, rdpsnd_server_thread, (
void*)context, 0,
nullptr);
996 if (!context->priv->Thread)
998 WLog_ERR(TAG,
"CreateThread failed!");
1003 return CHANNEL_RC_OK;
1005 (void)CloseHandle(context->priv->StopEvent);
1006 context->priv->StopEvent =
nullptr;
1008 DeleteCriticalSection(&context->priv->lock);
1010 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1011 context->priv->rdpsnd_pdu =
nullptr;
1013 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1014 context->priv->ChannelHandle =
nullptr;
1023static UINT rdpsnd_server_stop(RdpsndServerContext* context)
1025 UINT error = CHANNEL_RC_OK;
1027 WINPR_ASSERT(context);
1028 WINPR_ASSERT(context->priv);
1030 if (!context->priv->StopEvent)
1033 if (context->priv->ownThread)
1035 if (context->priv->StopEvent)
1037 (void)SetEvent(context->priv->StopEvent);
1039 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
1041 error = GetLastError();
1042 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
1046 (void)CloseHandle(context->priv->Thread);
1047 (void)CloseHandle(context->priv->StopEvent);
1048 context->priv->Thread =
nullptr;
1049 context->priv->StopEvent =
nullptr;
1053 DeleteCriticalSection(&context->priv->lock);
1055 if (context->priv->rdpsnd_pdu)
1057 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1058 context->priv->rdpsnd_pdu =
nullptr;
1061 if (context->priv->ChannelHandle)
1063 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1064 context->priv->ChannelHandle =
nullptr;
1070RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
1072 RdpsndServerPrivate* priv =
nullptr;
1073 RdpsndServerContext* context = (RdpsndServerContext*)calloc(1,
sizeof(RdpsndServerContext));
1079 context->Start = rdpsnd_server_start;
1080 context->Stop = rdpsnd_server_stop;
1081 context->selected_client_format = 0xFFFF;
1082 context->Initialize = rdpsnd_server_initialize;
1083 context->SendFormats = rdpsnd_server_send_formats;
1084 context->SelectFormat = rdpsnd_server_select_format;
1085 context->Training = rdpsnd_server_training;
1086 context->SendSamples = rdpsnd_server_send_samples;
1087 context->SendSamples2 = rdpsnd_server_send_samples2;
1088 context->SetVolume = rdpsnd_server_set_volume;
1089 context->Close = rdpsnd_server_close;
1090 context->priv = priv = (RdpsndServerPrivate*)calloc(1,
sizeof(RdpsndServerPrivate));
1094 WLog_ERR(TAG,
"calloc failed!");
1098 priv->dsp_context = freerdp_dsp_context_new(TRUE);
1100 if (!priv->dsp_context)
1102 WLog_ERR(TAG,
"freerdp_dsp_context_new failed!");
1106 priv->input_stream = Stream_New(
nullptr, 4);
1108 if (!priv->input_stream)
1110 WLog_ERR(TAG,
"Stream_New failed!");
1114 priv->expectedBytes = 4;
1115 priv->waitingHeader = TRUE;
1116 priv->ownThread = TRUE;
1119 WINPR_PRAGMA_DIAG_PUSH
1120 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1121 rdpsnd_server_context_free(context);
1122 WINPR_PRAGMA_DIAG_POP
1126void rdpsnd_server_context_reset(RdpsndServerContext* context)
1128 WINPR_ASSERT(context);
1129 WINPR_ASSERT(context->priv);
1131 context->priv->expectedBytes = 4;
1132 context->priv->waitingHeader = TRUE;
1133 Stream_ResetPosition(context->priv->input_stream);
1136void rdpsnd_server_context_free(RdpsndServerContext* context)
1143 rdpsnd_server_stop(context);
1145 free(context->priv->out_buffer);
1147 if (context->priv->dsp_context)
1148 freerdp_dsp_context_free(context->priv->dsp_context);
1150 if (context->priv->input_stream)
1151 Stream_Free(context->priv->input_stream, TRUE);
1154 free(context->server_formats);
1155 free(context->client_formats);
1156 free(context->priv);
1160HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context)
1162 WINPR_ASSERT(context);
1163 WINPR_ASSERT(context->priv);
1165 return context->priv->channelEvent;
1182UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
1184 DWORD bytesReturned = 0;
1185 UINT ret = CHANNEL_RC_OK;
1186 RdpsndServerPrivate* priv =
nullptr;
1189 WINPR_ASSERT(context);
1190 WINPR_ASSERT(context->priv);
1192 priv = context->priv;
1193 s = priv->input_stream;
1195 if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
1198 if (GetLastError() == ERROR_NO_DATA)
1199 return ERROR_NO_DATA;
1201 WLog_ERR(TAG,
"channel connection closed");
1202 return ERROR_INTERNAL_ERROR;
1205 priv->expectedBytes -= bytesReturned;
1206 Stream_Seek(s, bytesReturned);
1208 if (priv->expectedBytes)
1209 return CHANNEL_RC_OK;
1211 Stream_SealLength(s);
1212 Stream_ResetPosition(s);
1214 if (priv->waitingHeader)
1217 Stream_Read_UINT8(s, priv->msgType);
1218 Stream_Seek_UINT8(s);
1219 Stream_Read_UINT16(s, priv->expectedBytes);
1220 priv->waitingHeader = FALSE;
1221 Stream_ResetPosition(s);
1223 if (priv->expectedBytes)
1225 if (!Stream_EnsureCapacity(s, priv->expectedBytes))
1227 WLog_ERR(TAG,
"Stream_EnsureCapacity failed!");
1228 return CHANNEL_RC_NO_MEMORY;
1231 return CHANNEL_RC_OK;
1236#ifdef WITH_DEBUG_SND
1237 WLog_DBG(TAG,
"message type %" PRIu8
"", priv->msgType);
1239 priv->expectedBytes = 4;
1240 priv->waitingHeader = TRUE;
1242 switch (priv->msgType)
1244 case SNDC_WAVECONFIRM:
1245 ret = rdpsnd_server_recv_waveconfirm(context, s);
1249 ret = rdpsnd_server_recv_trainingconfirm(context, s);
1253 ret = rdpsnd_server_recv_formats(context, s);
1255 if ((ret == CHANNEL_RC_OK) && (context->clientVersion < CHANNEL_VERSION_WIN_7))
1256 IFCALL(context->Activated, context);
1260 case SNDC_QUALITYMODE:
1261 ret = rdpsnd_server_recv_quality_mode(context, s);
1263 if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7))
1264 IFCALL(context->Activated, context);
1269 WLog_ERR(TAG,
"UNKNOWN MESSAGE TYPE!! (0x%02" PRIX8
")", priv->msgType);
1270 ret = ERROR_INVALID_DATA;
1274 Stream_ResetPosition(s);