FreeRDP
Loading...
Searching...
No Matches
server/rdpsnd_main.c
1
22#include <freerdp/config.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include <winpr/crt.h>
29#include <winpr/assert.h>
30#include <winpr/cast.h>
31#include <winpr/print.h>
32#include <winpr/stream.h>
33
34#include <freerdp/freerdp.h>
35#include <freerdp/channels/log.h>
36
37#include "rdpsnd_common.h"
38#include "rdpsnd_main.h"
39
40static wStream* rdpsnd_server_get_buffer(RdpsndServerContext* context)
41{
42 wStream* s = nullptr;
43 WINPR_ASSERT(context);
44 WINPR_ASSERT(context->priv);
45
46 s = context->priv->rdpsnd_pdu;
47 Stream_ResetPosition(s);
48 return s;
49}
50
56static UINT rdpsnd_server_send_formats(RdpsndServerContext* context)
57{
58 wStream* s = rdpsnd_server_get_buffer(context);
59 BOOL status = FALSE;
60 ULONG written = 0;
61
62 if (!Stream_EnsureRemainingCapacity(s, 24))
63 return ERROR_OUTOFMEMORY;
64
65 Stream_Write_UINT8(s, SNDC_FORMATS);
66 Stream_Write_UINT8(s, 0);
67 Stream_Seek_UINT16(s);
68 Stream_Write_UINT32(s, 0); /* dwFlags */
69 Stream_Write_UINT32(s, 0); /* dwVolume */
70 Stream_Write_UINT32(s, 0); /* dwPitch */
71 Stream_Write_UINT16(s, 0); /* wDGramPort */
72 Stream_Write_UINT16(
73 s, WINPR_ASSERTING_INT_CAST(uint16_t, context->num_server_formats)); /* wNumberOfFormats */
74 Stream_Write_UINT8(s, context->block_no); /* cLastBlockConfirmed */
75 Stream_Write_UINT16(s, CHANNEL_VERSION_WIN_MAX); /* wVersion */
76 Stream_Write_UINT8(s, 0); /* bPad */
77
78 for (size_t i = 0; i < context->num_server_formats; i++)
79 {
80 const AUDIO_FORMAT* format = &context->server_formats[i];
81
82 if (!audio_format_write(s, format))
83 goto fail;
84 }
85
86 {
87 const size_t pos = Stream_GetPosition(s);
88 if (pos > UINT16_MAX)
89 goto fail;
90
91 WINPR_ASSERT(pos >= 4);
92 if (!Stream_SetPosition(s, 2))
93 goto fail;
94 Stream_Write_UINT16(s, (UINT16)(pos - 4));
95 if (!Stream_SetPosition(s, pos))
96 goto fail;
97
98 WINPR_ASSERT(context->priv);
99
100 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
101 (UINT32)pos, &written);
102 Stream_ResetPosition(s);
103 }
104fail:
105 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
106}
107
113static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream* s)
114{
115 UINT16 timestamp = 0;
116 BYTE confirmBlockNum = 0;
117 UINT error = CHANNEL_RC_OK;
118
119 WINPR_ASSERT(context);
120
121 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
122 return ERROR_INVALID_DATA;
123
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);
128
129 if (error)
130 WLog_ERR(TAG, "context->ConfirmBlock failed with error %" PRIu32 "", error);
131
132 return error;
133}
134
140static UINT rdpsnd_server_recv_trainingconfirm(RdpsndServerContext* context, wStream* s)
141{
142 UINT16 timestamp = 0;
143 UINT16 packsize = 0;
144 UINT error = CHANNEL_RC_OK;
145
146 WINPR_ASSERT(context);
147
148 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
149 return ERROR_INVALID_DATA;
150
151 Stream_Read_UINT16(s, timestamp);
152 Stream_Read_UINT16(s, packsize);
153
154 IFCALLRET(context->TrainingConfirm, error, context, timestamp, packsize);
155 if (error)
156 WLog_ERR(TAG, "context->TrainingConfirm failed with error %" PRIu32 "", error);
157
158 return error;
159}
160
166static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s)
167{
168 WINPR_ASSERT(context);
169
170 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
171 {
172 WLog_ERR(TAG, "not enough data in stream!");
173 return ERROR_INVALID_DATA;
174 }
175
176 Stream_Read_UINT16(s, context->qualityMode); /* wQualityMode */
177 Stream_Seek_UINT16(s); /* Reserved */
178
179 WLog_DBG(TAG, "Client requested sound quality: 0x%04" PRIX16 "", context->qualityMode);
180
181 return CHANNEL_RC_OK;
182}
183
189static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
190{
191 UINT error = CHANNEL_RC_OK;
192
193 WINPR_ASSERT(context);
194
195 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
196 return ERROR_INVALID_DATA;
197
198 Stream_Read_UINT32(s, context->capsFlags); /* dwFlags */
199 Stream_Read_UINT32(s, context->initialVolume); /* dwVolume */
200 Stream_Read_UINT32(s, context->initialPitch); /* dwPitch */
201 Stream_Read_UINT16(s, context->udpPort); /* wDGramPort */
202 Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */
203 Stream_Read_UINT8(s, context->lastblock); /* cLastBlockConfirmed */
204 Stream_Read_UINT16(s, context->clientVersion); /* wVersion */
205 Stream_Seek_UINT8(s); /* bPad */
206
207 /* this check is only a guess as cbSize can influence the size of a format record */
208 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, context->num_client_formats, 18ull))
209 return ERROR_INVALID_DATA;
210
211 if (!context->num_client_formats)
212 {
213 WLog_ERR(TAG, "client doesn't support any format!");
214 return ERROR_INTERNAL_ERROR;
215 }
216
217 context->client_formats = audio_formats_new(context->num_client_formats);
218
219 if (!context->client_formats)
220 {
221 WLog_ERR(TAG, "calloc failed!");
222 return CHANNEL_RC_NO_MEMORY;
223 }
224
225 for (UINT16 i = 0; i < context->num_client_formats; i++)
226 {
227 AUDIO_FORMAT* format = &context->client_formats[i];
228
229 if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
230 {
231 WLog_ERR(TAG, "not enough data in stream!");
232 error = ERROR_INVALID_DATA;
233 goto out_free;
234 }
235
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);
243
244 /* nChannels and nBlockAlign are used as divisors when sending audio
245 * (rdpsnd_server_align_wave_pdu: size % nBlockAlign; ADPCM frame sizing
246 * divides by nChannels). A malicious client can advertise a format with
247 * either field set to 0, causing a division by zero. No valid
248 * WAVEFORMATEX has zero channels or zero block alignment. */
249 if ((format->nChannels == 0) || (format->nBlockAlign == 0))
250 {
251 WLog_ERR(TAG, "invalid client audio format: nChannels or nBlockAlign is 0");
252 error = ERROR_INVALID_DATA;
253 goto out_free;
254 }
255
256 if (format->cbSize > 0)
257 {
258 if (!Stream_SafeSeek(s, format->cbSize))
259 {
260 WLog_ERR(TAG, "Stream_SafeSeek failed!");
261 error = ERROR_INTERNAL_ERROR;
262 goto out_free;
263 }
264 }
265 }
266
267 if (!context->num_client_formats)
268 {
269 WLog_ERR(TAG, "client doesn't support any known format!");
270 goto out_free;
271 }
272
273 return CHANNEL_RC_OK;
274out_free:
275 free(context->client_formats);
276 return error;
277}
278
279static DWORD WINAPI rdpsnd_server_thread(LPVOID arg)
280{
281 DWORD nCount = 0;
282 DWORD status = 0;
283 HANDLE events[2] = WINPR_C_ARRAY_INIT;
284 RdpsndServerContext* context = (RdpsndServerContext*)arg;
285 UINT error = CHANNEL_RC_OK;
286
287 WINPR_ASSERT(context);
288 WINPR_ASSERT(context->priv);
289
290 events[nCount++] = context->priv->channelEvent;
291 events[nCount++] = context->priv->StopEvent;
292
293 WINPR_ASSERT(nCount <= ARRAYSIZE(events));
294
295 while (TRUE)
296 {
297 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
298
299 if (status == WAIT_FAILED)
300 {
301 error = GetLastError();
302 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
303 break;
304 }
305
306 status = WaitForSingleObject(context->priv->StopEvent, 0);
307
308 if (status == WAIT_FAILED)
309 {
310 error = GetLastError();
311 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
312 break;
313 }
314
315 if (status == WAIT_OBJECT_0)
316 break;
317
318 if ((error = rdpsnd_server_handle_messages(context)))
319 {
320 WLog_ERR(TAG, "rdpsnd_server_handle_messages failed with error %" PRIu32 "", error);
321 break;
322 }
323 }
324
325 if (error && context->rdpcontext)
326 setChannelError(context->rdpcontext, error, "rdpsnd_server_thread reported an error");
327
328 ExitThread(error);
329 return error;
330}
331
337static UINT rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread)
338{
339 WINPR_ASSERT(context);
340 WINPR_ASSERT(context->priv);
341
342 context->priv->ownThread = ownThread;
343 return context->Start(context);
344}
345
351static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 client_format_index)
352{
353 size_t bs = 0;
354 size_t out_buffer_size = 0;
355 AUDIO_FORMAT* format = nullptr;
356 UINT error = CHANNEL_RC_OK;
357
358 WINPR_ASSERT(context);
359 WINPR_ASSERT(context->priv);
360
361 if ((client_format_index >= context->num_client_formats) || (!context->src_format))
362 {
363 WLog_ERR(TAG, "index %" PRIu16 " is not correct.", client_format_index);
364 return ERROR_INVALID_DATA;
365 }
366
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];
373
374 if (format->nSamplesPerSec == 0)
375 {
376 WLog_ERR(TAG, "invalid Client Sound Format!!");
377 error = ERROR_INVALID_DATA;
378 goto out;
379 }
380
381 if (context->latency <= 0)
382 context->latency = 50;
383
384 context->priv->out_frames = context->src_format->nSamplesPerSec * context->latency / 1000;
385
386 if (context->priv->out_frames < 1)
387 context->priv->out_frames = 1;
388
389 switch (format->wFormatTag)
390 {
391 case WAVE_FORMAT_DVI_ADPCM:
392 bs = 4ULL * (format->nBlockAlign - 4ULL * format->nChannels);
393 context->priv->out_frames -= context->priv->out_frames % bs;
394
395 if (context->priv->out_frames < bs)
396 context->priv->out_frames = bs;
397
398 break;
399
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;
403
404 if (context->priv->out_frames < bs)
405 context->priv->out_frames = bs;
406
407 break;
408 default:
409 break;
410 }
411
412 context->priv->out_pending_frames = 0;
413 out_buffer_size = context->priv->out_frames * context->priv->src_bytes_per_frame;
414
415 if (context->priv->out_buffer_size < out_buffer_size)
416 {
417 BYTE* newBuffer = nullptr;
418 newBuffer = (BYTE*)realloc(context->priv->out_buffer, out_buffer_size);
419
420 if (!newBuffer)
421 {
422 WLog_ERR(TAG, "realloc failed!");
423 error = CHANNEL_RC_NO_MEMORY;
424 goto out;
425 }
426
427 context->priv->out_buffer = newBuffer;
428 context->priv->out_buffer_size = out_buffer_size;
429 }
430
431 if (!freerdp_dsp_context_reset(context->priv->dsp_context, format, 0u))
432 error = ERROR_INTERNAL_ERROR;
433out:
434 LeaveCriticalSection(&context->priv->lock);
435 return error;
436}
437
443static UINT rdpsnd_server_training(RdpsndServerContext* context, UINT16 timestamp, UINT16 packsize,
444 BYTE* data)
445{
446 ULONG written = 0;
447 BOOL status = 0;
448 wStream* s = rdpsnd_server_get_buffer(context);
449
450 if (!Stream_EnsureRemainingCapacity(s, 8))
451 return ERROR_INTERNAL_ERROR;
452
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);
458
459 if (packsize > 0)
460 {
461 if (!Stream_EnsureRemainingCapacity(s, packsize))
462 {
463 Stream_ResetPosition(s);
464 return ERROR_INTERNAL_ERROR;
465 }
466
467 Stream_Write(s, data, packsize);
468 }
469
470 const size_t end = Stream_GetPosition(s);
471 if ((end < 4) || (end > UINT16_MAX))
472 return ERROR_INTERNAL_ERROR;
473
474 if (!Stream_SetPosition(s, 2))
475 return ERROR_INTERNAL_ERROR;
476 Stream_Write_UINT16(s, (UINT16)(end - 4));
477
478 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
479 (UINT32)end, &written);
480
481 Stream_ResetPosition(s);
482
483 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
484}
485
486static BOOL rdpsnd_server_align_wave_pdu(wStream* s, UINT32 alignment)
487{
488 size_t size = 0;
489 Stream_SealLength(s);
490 size = Stream_Length(s);
491
492 if ((size % alignment) != 0)
493 {
494 size_t offset = alignment - size % alignment;
495
496 if (!Stream_EnsureRemainingCapacity(s, offset))
497 return FALSE;
498
499 Stream_Zero(s, offset);
500 }
501
502 Stream_SealLength(s);
503 return TRUE;
504}
505
512static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
513{
514 AUDIO_FORMAT* format = nullptr;
515 ULONG written = 0;
516 UINT error = CHANNEL_RC_OK;
517 wStream* s = rdpsnd_server_get_buffer(context);
518
519 if (context->selected_client_format > context->num_client_formats)
520 return ERROR_INTERNAL_ERROR;
521
522 WINPR_ASSERT(context->client_formats);
523
524 format = &context->client_formats[context->selected_client_format];
525 /* WaveInfo PDU */
526 Stream_ResetPosition(s);
527
528 if (!Stream_EnsureRemainingCapacity(s, 16))
529 return ERROR_OUTOFMEMORY;
530
531 Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */
532 Stream_Write_UINT8(s, 0); /* bPad */
533 Stream_Write_UINT16(s, 0); /* BodySize */
534 Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */
535 Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */
536 Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
537 Stream_Seek(s, 3); /* bPad */
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;
542
543 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s))
544 return ERROR_INTERNAL_ERROR;
545
546 /* Set stream size */
547 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
548 return ERROR_INTERNAL_ERROR;
549
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;
559
560 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
561 (UINT32)(start + 4), &written))
562 {
563 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
564 error = ERROR_INTERNAL_ERROR;
565 }
566
567 if (error != CHANNEL_RC_OK)
568 {
569 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
570 error = ERROR_INTERNAL_ERROR;
571 goto out;
572 }
573
574 if (!Stream_SetPosition(s, start))
575 {
576 error = ERROR_INTERNAL_ERROR;
577 goto out;
578 }
579 Stream_Write_UINT32(s, 0); /* bPad */
580 if (!Stream_SetPosition(s, start))
581 {
582 error = ERROR_INTERNAL_ERROR;
583 goto out;
584 }
585
586 WINPR_ASSERT((end - start) <= UINT32_MAX);
587 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Pointer(s),
588 (UINT32)(end - start), &written))
589 {
590 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
591 error = ERROR_INTERNAL_ERROR;
592 }
593
594 context->block_no = (context->block_no + 1) % 256;
595
596out:
597 Stream_ResetPosition(s);
598 context->priv->out_pending_frames = 0;
599 return error;
600}
601
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)
611{
612 ULONG written = 0;
613 UINT error = CHANNEL_RC_OK;
614 BOOL status = 0;
615 wStream* s = rdpsnd_server_get_buffer(context);
616
617 if (!Stream_EnsureRemainingCapacity(s, 16))
618 {
619 error = ERROR_INTERNAL_ERROR;
620 goto out;
621 }
622
623 /* Wave2 PDU */
624 Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */
625 Stream_Write_UINT8(s, 0); /* bPad */
626 Stream_Write_UINT16(s, 0); /* BodySize */
627 Stream_Write_UINT16(s, timestamp); /* wTimeStamp */
628 Stream_Write_UINT16(s, formatNo); /* wFormatNo */
629 Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
630 Stream_Write_UINT8(s, 0); /* bPad */
631 Stream_Write_UINT8(s, 0); /* bPad */
632 Stream_Write_UINT8(s, 0); /* bPad */
633 Stream_Write_UINT32(s, audioTimeStamp); /* dwAudioTimeStamp */
634
635 if (encoded)
636 {
637 if (!Stream_EnsureRemainingCapacity(s, size))
638 {
639 error = ERROR_INTERNAL_ERROR;
640 goto out;
641 }
642
643 Stream_Write(s, data, size);
644 }
645 else
646 {
647 AUDIO_FORMAT* format = nullptr;
648
649 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, data, size, s))
650 {
651 error = ERROR_INTERNAL_ERROR;
652 goto out;
653 }
654
655 format = &context->client_formats[formatNo];
656 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
657 {
658 error = ERROR_INTERNAL_ERROR;
659 goto out;
660 }
661 }
662
663 {
664 const size_t end = Stream_GetPosition(s);
665 if (end > UINT16_MAX + 4)
666 {
667 error = ERROR_INTERNAL_ERROR;
668 goto out;
669 }
670
671 if (!Stream_SetPosition(s, 2))
672 {
673 error = ERROR_INTERNAL_ERROR;
674 goto out;
675 }
676 Stream_Write_UINT16(s, (UINT16)(end - 4));
677
678 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
679 (UINT32)end, &written);
680
681 if (!status || (end != written))
682 {
683 WLog_ERR(TAG,
684 "WTSVirtualChannelWrite failed! [stream length=%" PRIuz " - written=%" PRIu32,
685 end, written);
686 error = ERROR_INTERNAL_ERROR;
687 }
688 }
689
690 context->block_no = (context->block_no + 1) % 256;
691
692out:
693 Stream_ResetPosition(s);
694 context->priv->out_pending_frames = 0;
695 return error;
696}
697
698/* Wrapper function to send WAVE or WAVE2 PDU depending on client connected */
699static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
700{
701 const BYTE* src = nullptr;
702 size_t length = 0;
703
704 WINPR_ASSERT(context);
705 WINPR_ASSERT(context->priv);
706
707 if (context->selected_client_format >= context->num_client_formats)
708 return ERROR_INTERNAL_ERROR;
709
710 src = context->priv->out_buffer;
711 length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
712
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);
716 else
717 return rdpsnd_server_send_wave_pdu(context, wTimestamp);
718}
719
725static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf,
726 size_t nframes, UINT16 wTimestamp)
727{
728 UINT error = CHANNEL_RC_OK;
729
730 WINPR_ASSERT(context);
731 WINPR_ASSERT(context->priv);
732
733 EnterCriticalSection(&context->priv->lock);
734
735 if (context->selected_client_format >= context->num_client_formats)
736 {
737 /* It's possible while format negotiation has not been done */
738 WLog_WARN(TAG, "Drop samples because client format has not been negotiated.");
739 error = ERROR_NOT_READY;
740 goto out;
741 }
742
743 while (nframes > 0)
744 {
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),
750 buf, cframesize);
751 buf = (const BYTE*)buf + cframesize;
752 nframes -= cframes;
753 context->priv->out_pending_frames += cframes;
754
755 if (context->priv->out_pending_frames >= context->priv->out_frames)
756 {
757 if ((error = rdpsnd_server_send_audio_pdu(context, wTimestamp)))
758 {
759 WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error);
760 break;
761 }
762 }
763 }
764
765out:
766 LeaveCriticalSection(&context->priv->lock);
767 return error;
768}
769
775static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 formatNo,
776 const void* buf, size_t size, UINT16 timestamp,
777 UINT32 audioTimeStamp)
778{
779 UINT error = CHANNEL_RC_OK;
780
781 WINPR_ASSERT(context);
782 WINPR_ASSERT(context->priv);
783
784 if (context->clientVersion < CHANNEL_VERSION_WIN_8)
785 return ERROR_INTERNAL_ERROR;
786
787 EnterCriticalSection(&context->priv->lock);
788
789 error =
790 rdpsnd_server_send_wave2_pdu(context, formatNo, buf, size, TRUE, timestamp, audioTimeStamp);
791
792 LeaveCriticalSection(&context->priv->lock);
793
794 return error;
795}
796
802static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, UINT16 left, UINT16 right)
803{
804 BOOL status = 0;
805 ULONG written = 0;
806 wStream* s = rdpsnd_server_get_buffer(context);
807
808 if (!Stream_EnsureRemainingCapacity(s, 8))
809 return ERROR_NOT_ENOUGH_MEMORY;
810
811 Stream_Write_UINT8(s, SNDC_SETVOLUME);
812 Stream_Write_UINT8(s, 0);
813 Stream_Write_UINT16(s, 4); /* Payload length */
814 Stream_Write_UINT16(s, left);
815 Stream_Write_UINT16(s, right);
816
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;
823}
824
830static UINT rdpsnd_server_close(RdpsndServerContext* context)
831{
832 BOOL status = 0;
833 ULONG written = 0;
834 UINT error = CHANNEL_RC_OK;
835 wStream* s = rdpsnd_server_get_buffer(context);
836
837 EnterCriticalSection(&context->priv->lock);
838
839 if (context->priv->out_pending_frames > 0)
840 {
841 if (context->selected_client_format >= context->num_client_formats)
842 {
843 WLog_ERR(TAG, "Pending audio frame exists while no format selected.");
844 error = ERROR_INVALID_DATA;
845 }
846 else if ((error = rdpsnd_server_send_audio_pdu(context, 0)))
847 {
848 WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error);
849 }
850 }
851
852 LeaveCriticalSection(&context->priv->lock);
853
854 if (error)
855 return error;
856
857 context->selected_client_format = 0xFFFF;
858
859 if (!Stream_EnsureRemainingCapacity(s, 4))
860 return ERROR_OUTOFMEMORY;
861
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;
872
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;
879}
880
886static UINT rdpsnd_server_start(RdpsndServerContext* context)
887{
888 void* buffer = nullptr;
889 DWORD bytesReturned = 0;
890 RdpsndServerPrivate* priv = nullptr;
891 UINT error = ERROR_INTERNAL_ERROR;
892 PULONG pSessionId = nullptr;
893
894 WINPR_ASSERT(context);
895 WINPR_ASSERT(context->priv);
896
897 priv = context->priv;
898 priv->SessionId = WTS_CURRENT_SESSION;
899
900 if (context->use_dynamic_virtual_channel)
901 {
902 UINT32 channelId = 0;
903 BOOL status = TRUE;
904
905 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
906 (LPSTR*)&pSessionId, &bytesReturned))
907 {
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)
913 {
914 WLog_ERR(TAG, "Open audio dynamic virtual channel (%s) failed!",
915 RDPSND_DVC_CHANNEL_NAME);
916 return ERROR_INTERNAL_ERROR;
917 }
918
919 channelId = WTSChannelGetIdByHandle(priv->ChannelHandle);
920
921 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
922 if (!status)
923 {
924 WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
925 goto out_close;
926 }
927 }
928 else
929 {
930 WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
931 return ERROR_INTERNAL_ERROR;
932 }
933 }
934 else
935 {
936 priv->ChannelHandle =
937 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPSND_CHANNEL_NAME);
938 if (!priv->ChannelHandle)
939 {
940 WLog_ERR(TAG, "Open audio static virtual channel (rdpsnd) failed!");
941 return ERROR_INTERNAL_ERROR;
942 }
943 }
944
945 if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
946 &bytesReturned) ||
947 (bytesReturned != sizeof(HANDLE)))
948 {
949 WLog_ERR(TAG,
950 "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned "
951 "size(%" PRIu32 ")",
952 bytesReturned);
953
954 if (buffer)
955 WTSFreeMemory(buffer);
956
957 goto out_close;
958 }
959
960 priv->channelEvent = *(HANDLE*)buffer;
961 WTSFreeMemory(buffer);
962 priv->rdpsnd_pdu = Stream_New(nullptr, 4096);
963
964 if (!priv->rdpsnd_pdu)
965 {
966 WLog_ERR(TAG, "Stream_New failed!");
967 error = CHANNEL_RC_NO_MEMORY;
968 goto out_close;
969 }
970
971 if (!InitializeCriticalSectionEx(&context->priv->lock, 0, 0))
972 {
973 WLog_ERR(TAG, "InitializeCriticalSectionEx failed!");
974 goto out_pdu;
975 }
976
977 if ((error = rdpsnd_server_send_formats(context)))
978 {
979 WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %" PRIu32 "", error);
980 goto out_lock;
981 }
982
983 if (priv->ownThread)
984 {
985 context->priv->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
986
987 if (!context->priv->StopEvent)
988 {
989 WLog_ERR(TAG, "CreateEvent failed!");
990 goto out_lock;
991 }
992
993 context->priv->Thread =
994 CreateThread(nullptr, 0, rdpsnd_server_thread, (void*)context, 0, nullptr);
995
996 if (!context->priv->Thread)
997 {
998 WLog_ERR(TAG, "CreateThread failed!");
999 goto out_stopEvent;
1000 }
1001 }
1002
1003 return CHANNEL_RC_OK;
1004out_stopEvent:
1005 (void)CloseHandle(context->priv->StopEvent);
1006 context->priv->StopEvent = nullptr;
1007out_lock:
1008 DeleteCriticalSection(&context->priv->lock);
1009out_pdu:
1010 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1011 context->priv->rdpsnd_pdu = nullptr;
1012out_close:
1013 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1014 context->priv->ChannelHandle = nullptr;
1015 return error;
1016}
1017
1023static UINT rdpsnd_server_stop(RdpsndServerContext* context)
1024{
1025 UINT error = CHANNEL_RC_OK;
1026
1027 WINPR_ASSERT(context);
1028 WINPR_ASSERT(context->priv);
1029
1030 if (!context->priv->StopEvent)
1031 return error;
1032
1033 if (context->priv->ownThread)
1034 {
1035 if (context->priv->StopEvent)
1036 {
1037 (void)SetEvent(context->priv->StopEvent);
1038
1039 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
1040 {
1041 error = GetLastError();
1042 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
1043 return error;
1044 }
1045
1046 (void)CloseHandle(context->priv->Thread);
1047 (void)CloseHandle(context->priv->StopEvent);
1048 context->priv->Thread = nullptr;
1049 context->priv->StopEvent = nullptr;
1050 }
1051 }
1052
1053 DeleteCriticalSection(&context->priv->lock);
1054
1055 if (context->priv->rdpsnd_pdu)
1056 {
1057 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1058 context->priv->rdpsnd_pdu = nullptr;
1059 }
1060
1061 if (context->priv->ChannelHandle)
1062 {
1063 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1064 context->priv->ChannelHandle = nullptr;
1065 }
1066
1067 return error;
1068}
1069
1070RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
1071{
1072 RdpsndServerPrivate* priv = nullptr;
1073 RdpsndServerContext* context = (RdpsndServerContext*)calloc(1, sizeof(RdpsndServerContext));
1074
1075 if (!context)
1076 goto fail;
1077
1078 context->vcm = vcm;
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));
1091
1092 if (!priv)
1093 {
1094 WLog_ERR(TAG, "calloc failed!");
1095 goto fail;
1096 }
1097
1098 priv->dsp_context = freerdp_dsp_context_new(TRUE);
1099
1100 if (!priv->dsp_context)
1101 {
1102 WLog_ERR(TAG, "freerdp_dsp_context_new failed!");
1103 goto fail;
1104 }
1105
1106 priv->input_stream = Stream_New(nullptr, 4);
1107
1108 if (!priv->input_stream)
1109 {
1110 WLog_ERR(TAG, "Stream_New failed!");
1111 goto fail;
1112 }
1113
1114 priv->expectedBytes = 4;
1115 priv->waitingHeader = TRUE;
1116 priv->ownThread = TRUE;
1117 return context;
1118fail:
1119 WINPR_PRAGMA_DIAG_PUSH
1120 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1121 rdpsnd_server_context_free(context);
1122 WINPR_PRAGMA_DIAG_POP
1123 return nullptr;
1124}
1125
1126void rdpsnd_server_context_reset(RdpsndServerContext* context)
1127{
1128 WINPR_ASSERT(context);
1129 WINPR_ASSERT(context->priv);
1130
1131 context->priv->expectedBytes = 4;
1132 context->priv->waitingHeader = TRUE;
1133 Stream_ResetPosition(context->priv->input_stream);
1134}
1135
1136void rdpsnd_server_context_free(RdpsndServerContext* context)
1137{
1138 if (!context)
1139 return;
1140
1141 if (context->priv)
1142 {
1143 rdpsnd_server_stop(context);
1144
1145 free(context->priv->out_buffer);
1146
1147 if (context->priv->dsp_context)
1148 freerdp_dsp_context_free(context->priv->dsp_context);
1149
1150 if (context->priv->input_stream)
1151 Stream_Free(context->priv->input_stream, TRUE);
1152 }
1153
1154 free(context->server_formats);
1155 free(context->client_formats);
1156 free(context->priv);
1157 free(context);
1158}
1159
1160HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context)
1161{
1162 WINPR_ASSERT(context);
1163 WINPR_ASSERT(context->priv);
1164
1165 return context->priv->channelEvent;
1166}
1167
1168/*
1169 * Handle rpdsnd messages - server side
1170 *
1171 * @param Server side context
1172 *
1173 * @return 0 on success
1174 * ERROR_NO_DATA if no data could be read this time
1175 * otherwise error
1176 */
1182UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
1183{
1184 DWORD bytesReturned = 0;
1185 UINT ret = CHANNEL_RC_OK;
1186 RdpsndServerPrivate* priv = nullptr;
1187 wStream* s = nullptr;
1188
1189 WINPR_ASSERT(context);
1190 WINPR_ASSERT(context->priv);
1191
1192 priv = context->priv;
1193 s = priv->input_stream;
1194
1195 if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
1196 &bytesReturned))
1197 {
1198 if (GetLastError() == ERROR_NO_DATA)
1199 return ERROR_NO_DATA;
1200
1201 WLog_ERR(TAG, "channel connection closed");
1202 return ERROR_INTERNAL_ERROR;
1203 }
1204
1205 priv->expectedBytes -= bytesReturned;
1206 Stream_Seek(s, bytesReturned);
1207
1208 if (priv->expectedBytes)
1209 return CHANNEL_RC_OK;
1210
1211 Stream_SealLength(s);
1212 Stream_ResetPosition(s);
1213
1214 if (priv->waitingHeader)
1215 {
1216 /* header case */
1217 Stream_Read_UINT8(s, priv->msgType);
1218 Stream_Seek_UINT8(s); /* bPad */
1219 Stream_Read_UINT16(s, priv->expectedBytes);
1220 priv->waitingHeader = FALSE;
1221 Stream_ResetPosition(s);
1222
1223 if (priv->expectedBytes)
1224 {
1225 if (!Stream_EnsureCapacity(s, priv->expectedBytes))
1226 {
1227 WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
1228 return CHANNEL_RC_NO_MEMORY;
1229 }
1230
1231 return CHANNEL_RC_OK;
1232 }
1233 }
1234
1235 /* when here we have the header + the body */
1236#ifdef WITH_DEBUG_SND
1237 WLog_DBG(TAG, "message type %" PRIu8 "", priv->msgType);
1238#endif
1239 priv->expectedBytes = 4;
1240 priv->waitingHeader = TRUE;
1241
1242 switch (priv->msgType)
1243 {
1244 case SNDC_WAVECONFIRM:
1245 ret = rdpsnd_server_recv_waveconfirm(context, s);
1246 break;
1247
1248 case SNDC_TRAINING:
1249 ret = rdpsnd_server_recv_trainingconfirm(context, s);
1250 break;
1251
1252 case SNDC_FORMATS:
1253 ret = rdpsnd_server_recv_formats(context, s);
1254
1255 if ((ret == CHANNEL_RC_OK) && (context->clientVersion < CHANNEL_VERSION_WIN_7))
1256 IFCALL(context->Activated, context);
1257
1258 break;
1259
1260 case SNDC_QUALITYMODE:
1261 ret = rdpsnd_server_recv_quality_mode(context, s);
1262
1263 if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7))
1264 IFCALL(context->Activated, context);
1265
1266 break;
1267
1268 default:
1269 WLog_ERR(TAG, "UNKNOWN MESSAGE TYPE!! (0x%02" PRIX8 ")", priv->msgType);
1270 ret = ERROR_INVALID_DATA;
1271 break;
1272 }
1273
1274 Stream_ResetPosition(s);
1275 return ret;
1276}