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
184static void rdpsnd_server_client_format_free(RdpsndServerContext* context)
185{
186 WINPR_ASSERT(context);
187 free(context->client_formats);
188 context->client_formats = nullptr;
189 context->num_client_formats = 0;
190}
191
197static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
198{
199 UINT error = CHANNEL_RC_OK;
200
201 WINPR_ASSERT(context);
202
203 if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
204 return ERROR_INVALID_DATA;
205
206 Stream_Read_UINT32(s, context->capsFlags); /* dwFlags */
207 Stream_Read_UINT32(s, context->initialVolume); /* dwVolume */
208 Stream_Read_UINT32(s, context->initialPitch); /* dwPitch */
209 Stream_Read_UINT16(s, context->udpPort); /* wDGramPort */
210 Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */
211 Stream_Read_UINT8(s, context->lastblock); /* cLastBlockConfirmed */
212 Stream_Read_UINT16(s, context->clientVersion); /* wVersion */
213 Stream_Seek_UINT8(s); /* bPad */
214
215 /* this check is only a guess as cbSize can influence the size of a format record */
216 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, context->num_client_formats, 18ull))
217 return ERROR_INVALID_DATA;
218
219 if (!context->num_client_formats)
220 {
221 WLog_ERR(TAG, "client doesn't support any format!");
222 return ERROR_INTERNAL_ERROR;
223 }
224
225 context->client_formats = audio_formats_new(context->num_client_formats);
226
227 if (!context->client_formats)
228 {
229 WLog_ERR(TAG, "calloc failed!");
230 return CHANNEL_RC_NO_MEMORY;
231 }
232
233 for (UINT16 i = 0; i < context->num_client_formats; i++)
234 {
235 AUDIO_FORMAT* format = &context->client_formats[i];
236
237 if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
238 {
239 WLog_ERR(TAG, "not enough data in stream!");
240 error = ERROR_INVALID_DATA;
241 goto out_free;
242 }
243
244 Stream_Read_UINT16(s, format->wFormatTag);
245 Stream_Read_UINT16(s, format->nChannels);
246 Stream_Read_UINT32(s, format->nSamplesPerSec);
247 Stream_Read_UINT32(s, format->nAvgBytesPerSec);
248 Stream_Read_UINT16(s, format->nBlockAlign);
249 Stream_Read_UINT16(s, format->wBitsPerSample);
250 Stream_Read_UINT16(s, format->cbSize);
251
252 /* nChannels and nBlockAlign are used as divisors when sending audio
253 * (rdpsnd_server_align_wave_pdu: size % nBlockAlign; ADPCM frame sizing
254 * divides by nChannels). A malicious client can advertise a format with
255 * either field set to 0, causing a division by zero. No valid
256 * WAVEFORMATEX has zero channels or zero block alignment. */
257 if ((format->nChannels == 0) || (format->nBlockAlign == 0))
258 {
259 WLog_ERR(TAG, "invalid client audio format: nChannels or nBlockAlign is 0");
260 error = ERROR_INVALID_DATA;
261 goto out_free;
262 }
263
264 /* Some wave formats have stricter requirements */
265 switch (format->wFormatTag)
266 {
267 case WAVE_FORMAT_DVI_ADPCM:
268 if (format->nBlockAlign < 4)
269 {
270 WLog_ERR(TAG,
271 "invalid client audio format %s: nBlockAlign is %" PRIu32
272 ", must be >= 4",
273 audio_format_get_tag_string(format->wFormatTag), format->nBlockAlign);
274 error = ERROR_INVALID_DATA;
275 goto out_free;
276 }
277 break;
278 case WAVE_FORMAT_ADPCM:
279 if (format->nBlockAlign < 8)
280 {
281 WLog_ERR(TAG,
282 "invalid client audio format %s: nBlockAlign is %" PRIu32
283 ", must be >= 8",
284 audio_format_get_tag_string(format->wFormatTag), format->nBlockAlign);
285 error = ERROR_INVALID_DATA;
286 goto out_free;
287 }
288 break;
289 default:
290 break;
291 }
292
293 if (format->cbSize > 0)
294 {
295 if (!Stream_SafeSeek(s, format->cbSize))
296 {
297 WLog_ERR(TAG, "Stream_SafeSeek failed!");
298 error = ERROR_INTERNAL_ERROR;
299 goto out_free;
300 }
301 }
302 }
303
304 if (!context->num_client_formats)
305 {
306 WLog_ERR(TAG, "client doesn't support any known format!");
307 goto out_free;
308 }
309
310 return CHANNEL_RC_OK;
311out_free:
312 rdpsnd_server_client_format_free(context);
313 return error;
314}
315
316static DWORD WINAPI rdpsnd_server_thread(LPVOID arg)
317{
318 DWORD nCount = 0;
319 DWORD status = 0;
320 HANDLE events[2] = WINPR_C_ARRAY_INIT;
321 RdpsndServerContext* context = (RdpsndServerContext*)arg;
322 UINT error = CHANNEL_RC_OK;
323
324 WINPR_ASSERT(context);
325 WINPR_ASSERT(context->priv);
326
327 events[nCount++] = context->priv->channelEvent;
328 events[nCount++] = context->priv->StopEvent;
329
330 WINPR_ASSERT(nCount <= ARRAYSIZE(events));
331
332 while (TRUE)
333 {
334 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
335
336 if (status == WAIT_FAILED)
337 {
338 error = GetLastError();
339 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
340 break;
341 }
342
343 status = WaitForSingleObject(context->priv->StopEvent, 0);
344
345 if (status == WAIT_FAILED)
346 {
347 error = GetLastError();
348 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
349 break;
350 }
351
352 if (status == WAIT_OBJECT_0)
353 break;
354
355 if ((error = rdpsnd_server_handle_messages(context)))
356 {
357 WLog_ERR(TAG, "rdpsnd_server_handle_messages failed with error %" PRIu32 "", error);
358 break;
359 }
360 }
361
362 if (error && context->rdpcontext)
363 setChannelError(context->rdpcontext, error, "rdpsnd_server_thread reported an error");
364
365 ExitThread(error);
366 return error;
367}
368
374static UINT rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread)
375{
376 WINPR_ASSERT(context);
377 WINPR_ASSERT(context->priv);
378
379 context->priv->ownThread = ownThread;
380 return context->Start(context);
381}
382
388static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 client_format_index)
389{
390 size_t out_buffer_size = 0;
391 AUDIO_FORMAT* format = nullptr;
392 UINT error = CHANNEL_RC_OK;
393
394 WINPR_ASSERT(context);
395 WINPR_ASSERT(context->priv);
396
397 if ((client_format_index >= context->num_client_formats) || (!context->src_format))
398 {
399 WLog_ERR(TAG, "index %" PRIu16 " is not correct.", client_format_index);
400 return ERROR_INVALID_DATA;
401 }
402
403 EnterCriticalSection(&context->priv->lock);
404 context->priv->src_bytes_per_sample = context->src_format->wBitsPerSample / 8;
405 context->priv->src_bytes_per_frame =
406 context->priv->src_bytes_per_sample * context->src_format->nChannels;
407 context->selected_client_format = client_format_index;
408 format = &context->client_formats[client_format_index];
409
410 if (format->nSamplesPerSec == 0)
411 {
412 WLog_ERR(TAG, "invalid Client Sound Format!!");
413 error = ERROR_INVALID_DATA;
414 goto out;
415 }
416
417 if (context->latency <= 0)
418 context->latency = 50;
419
420 context->priv->out_frames = context->src_format->nSamplesPerSec * context->latency / 1000;
421
422 if (context->priv->out_frames < 1)
423 context->priv->out_frames = 1;
424
425 switch (format->wFormatTag)
426 {
427 case WAVE_FORMAT_DVI_ADPCM:
428 {
429 WINPR_ASSERT(format->nBlockAlign >= 4);
430 WINPR_ASSERT(format->nChannels > 0);
431 const UINT64 bs = 4ULL * (format->nBlockAlign - 4ULL * format->nChannels);
432 WINPR_ASSERT(bs > 0);
433
434 context->priv->out_frames -= context->priv->out_frames % bs;
435
436 if (context->priv->out_frames < bs)
437 context->priv->out_frames = bs;
438 }
439 break;
440
441 case WAVE_FORMAT_ADPCM:
442 {
443 WINPR_ASSERT(format->nBlockAlign >= 8);
444 WINPR_ASSERT(format->nChannels > 0);
445
446 const UINT64 bs =
447 (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2;
448 WINPR_ASSERT(bs > 0);
449 context->priv->out_frames -= context->priv->out_frames % bs;
450
451 if (context->priv->out_frames < bs)
452 context->priv->out_frames = bs;
453 }
454 break;
455 default:
456 break;
457 }
458
459 context->priv->out_pending_frames = 0;
460 out_buffer_size = context->priv->out_frames * context->priv->src_bytes_per_frame;
461
462 if (context->priv->out_buffer_size < out_buffer_size)
463 {
464 BYTE* newBuffer = nullptr;
465 newBuffer = (BYTE*)realloc(context->priv->out_buffer, out_buffer_size);
466
467 if (!newBuffer)
468 {
469 WLog_ERR(TAG, "realloc failed!");
470 error = CHANNEL_RC_NO_MEMORY;
471 goto out;
472 }
473
474 context->priv->out_buffer = newBuffer;
475 context->priv->out_buffer_size = out_buffer_size;
476 }
477
478 if (!freerdp_dsp_context_reset(context->priv->dsp_context, format, 0u))
479 error = ERROR_INTERNAL_ERROR;
480out:
481 LeaveCriticalSection(&context->priv->lock);
482 return error;
483}
484
490static UINT rdpsnd_server_training(RdpsndServerContext* context, UINT16 timestamp, UINT16 packsize,
491 BYTE* data)
492{
493 ULONG written = 0;
494 BOOL status = 0;
495 wStream* s = rdpsnd_server_get_buffer(context);
496
497 if (!Stream_EnsureRemainingCapacity(s, 8))
498 return ERROR_INTERNAL_ERROR;
499
500 Stream_Write_UINT8(s, SNDC_TRAINING);
501 Stream_Write_UINT8(s, 0);
502 Stream_Seek_UINT16(s);
503 Stream_Write_UINT16(s, timestamp);
504 Stream_Write_UINT16(s, packsize);
505
506 if (packsize > 0)
507 {
508 if (!Stream_EnsureRemainingCapacity(s, packsize))
509 {
510 Stream_ResetPosition(s);
511 return ERROR_INTERNAL_ERROR;
512 }
513
514 Stream_Write(s, data, packsize);
515 }
516
517 const size_t end = Stream_GetPosition(s);
518 if ((end < 4) || (end > UINT16_MAX))
519 return ERROR_INTERNAL_ERROR;
520
521 if (!Stream_SetPosition(s, 2))
522 return ERROR_INTERNAL_ERROR;
523 Stream_Write_UINT16(s, (UINT16)(end - 4));
524
525 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
526 (UINT32)end, &written);
527
528 Stream_ResetPosition(s);
529
530 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
531}
532
533static BOOL rdpsnd_server_align_wave_pdu(wStream* s, UINT32 alignment)
534{
535 size_t size = 0;
536 Stream_SealLength(s);
537 size = Stream_Length(s);
538
539 if ((size % alignment) != 0)
540 {
541 size_t offset = alignment - size % alignment;
542
543 if (!Stream_EnsureRemainingCapacity(s, offset))
544 return FALSE;
545
546 Stream_Zero(s, offset);
547 }
548
549 Stream_SealLength(s);
550 return TRUE;
551}
552
559static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
560{
561 AUDIO_FORMAT* format = nullptr;
562 ULONG written = 0;
563 UINT error = CHANNEL_RC_OK;
564 wStream* s = rdpsnd_server_get_buffer(context);
565
566 if (context->selected_client_format > context->num_client_formats)
567 return ERROR_INTERNAL_ERROR;
568
569 WINPR_ASSERT(context->client_formats);
570
571 format = &context->client_formats[context->selected_client_format];
572 /* WaveInfo PDU */
573 Stream_ResetPosition(s);
574
575 if (!Stream_EnsureRemainingCapacity(s, 16))
576 return ERROR_OUTOFMEMORY;
577
578 Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */
579 Stream_Write_UINT8(s, 0); /* bPad */
580 Stream_Write_UINT16(s, 0); /* BodySize */
581 Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */
582 Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */
583 Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
584 Stream_Seek(s, 3); /* bPad */
585 const size_t start = Stream_GetPosition(s);
586 const BYTE* src = context->priv->out_buffer;
587 const size_t length =
588 1ull * context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
589
590 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s))
591 return ERROR_INTERNAL_ERROR;
592
593 /* Set stream size */
594 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
595 return ERROR_INTERNAL_ERROR;
596
597 const size_t end = Stream_GetPosition(s);
598 const size_t pos = end - start + 8ULL;
599 if (pos > UINT16_MAX)
600 return ERROR_INTERNAL_ERROR;
601 if (!Stream_SetPosition(s, 2))
602 return ERROR_INTERNAL_ERROR;
603 Stream_Write_UINT16(s, (UINT16)pos);
604 if (!Stream_SetPosition(s, end))
605 return ERROR_INTERNAL_ERROR;
606
607 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
608 (UINT32)(start + 4), &written))
609 {
610 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
611 error = ERROR_INTERNAL_ERROR;
612 }
613
614 if (error != CHANNEL_RC_OK)
615 {
616 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
617 error = ERROR_INTERNAL_ERROR;
618 goto out;
619 }
620
621 if (!Stream_SetPosition(s, start))
622 {
623 error = ERROR_INTERNAL_ERROR;
624 goto out;
625 }
626 Stream_Write_UINT32(s, 0); /* bPad */
627 if (!Stream_SetPosition(s, start))
628 {
629 error = ERROR_INTERNAL_ERROR;
630 goto out;
631 }
632
633 WINPR_ASSERT((end - start) <= UINT32_MAX);
634 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Pointer(s),
635 (UINT32)(end - start), &written))
636 {
637 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
638 error = ERROR_INTERNAL_ERROR;
639 }
640
641 context->block_no = (context->block_no + 1) % 256;
642
643out:
644 Stream_ResetPosition(s);
645 context->priv->out_pending_frames = 0;
646 return error;
647}
648
655static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 formatNo,
656 const BYTE* data, size_t size, BOOL encoded,
657 UINT16 timestamp, UINT32 audioTimeStamp)
658{
659 ULONG written = 0;
660 UINT error = CHANNEL_RC_OK;
661 BOOL status = 0;
662 wStream* s = rdpsnd_server_get_buffer(context);
663
664 if (!Stream_EnsureRemainingCapacity(s, 16))
665 {
666 error = ERROR_INTERNAL_ERROR;
667 goto out;
668 }
669
670 /* Wave2 PDU */
671 Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */
672 Stream_Write_UINT8(s, 0); /* bPad */
673 Stream_Write_UINT16(s, 0); /* BodySize */
674 Stream_Write_UINT16(s, timestamp); /* wTimeStamp */
675 Stream_Write_UINT16(s, formatNo); /* wFormatNo */
676 Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
677 Stream_Write_UINT8(s, 0); /* bPad */
678 Stream_Write_UINT8(s, 0); /* bPad */
679 Stream_Write_UINT8(s, 0); /* bPad */
680 Stream_Write_UINT32(s, audioTimeStamp); /* dwAudioTimeStamp */
681
682 if (encoded)
683 {
684 if (!Stream_EnsureRemainingCapacity(s, size))
685 {
686 error = ERROR_INTERNAL_ERROR;
687 goto out;
688 }
689
690 Stream_Write(s, data, size);
691 }
692 else
693 {
694 AUDIO_FORMAT* format = nullptr;
695
696 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, data, size, s))
697 {
698 error = ERROR_INTERNAL_ERROR;
699 goto out;
700 }
701
702 format = &context->client_formats[formatNo];
703 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
704 {
705 error = ERROR_INTERNAL_ERROR;
706 goto out;
707 }
708 }
709
710 {
711 const size_t end = Stream_GetPosition(s);
712 if (end > UINT16_MAX + 4)
713 {
714 error = ERROR_INTERNAL_ERROR;
715 goto out;
716 }
717
718 if (!Stream_SetPosition(s, 2))
719 {
720 error = ERROR_INTERNAL_ERROR;
721 goto out;
722 }
723 Stream_Write_UINT16(s, (UINT16)(end - 4));
724
725 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
726 (UINT32)end, &written);
727
728 if (!status || (end != written))
729 {
730 WLog_ERR(TAG,
731 "WTSVirtualChannelWrite failed! [stream length=%" PRIuz " - written=%" PRIu32,
732 end, written);
733 error = ERROR_INTERNAL_ERROR;
734 }
735 }
736
737 context->block_no = (context->block_no + 1) % 256;
738
739out:
740 Stream_ResetPosition(s);
741 context->priv->out_pending_frames = 0;
742 return error;
743}
744
745/* Wrapper function to send WAVE or WAVE2 PDU depending on client connected */
746static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
747{
748 const BYTE* src = nullptr;
749 size_t length = 0;
750
751 WINPR_ASSERT(context);
752 WINPR_ASSERT(context->priv);
753
754 if (context->selected_client_format >= context->num_client_formats)
755 return ERROR_INTERNAL_ERROR;
756
757 src = context->priv->out_buffer;
758 length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
759
760 if (context->clientVersion >= CHANNEL_VERSION_WIN_8)
761 return rdpsnd_server_send_wave2_pdu(context, context->selected_client_format, src, length,
762 FALSE, wTimestamp, wTimestamp);
763 else
764 return rdpsnd_server_send_wave_pdu(context, wTimestamp);
765}
766
772static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf,
773 size_t nframes, UINT16 wTimestamp)
774{
775 UINT error = CHANNEL_RC_OK;
776
777 WINPR_ASSERT(context);
778 WINPR_ASSERT(context->priv);
779
780 EnterCriticalSection(&context->priv->lock);
781
782 if (context->selected_client_format >= context->num_client_formats)
783 {
784 /* It's possible while format negotiation has not been done */
785 WLog_WARN(TAG, "Drop samples because client format has not been negotiated.");
786 error = ERROR_NOT_READY;
787 goto out;
788 }
789
790 while (nframes > 0)
791 {
792 const size_t cframes =
793 MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames);
794 size_t cframesize = cframes * context->priv->src_bytes_per_frame;
795 CopyMemory(context->priv->out_buffer +
796 (context->priv->out_pending_frames * context->priv->src_bytes_per_frame),
797 buf, cframesize);
798 buf = (const BYTE*)buf + cframesize;
799 nframes -= cframes;
800 context->priv->out_pending_frames += cframes;
801
802 if (context->priv->out_pending_frames >= context->priv->out_frames)
803 {
804 if ((error = rdpsnd_server_send_audio_pdu(context, wTimestamp)))
805 {
806 WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error);
807 break;
808 }
809 }
810 }
811
812out:
813 LeaveCriticalSection(&context->priv->lock);
814 return error;
815}
816
822static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 formatNo,
823 const void* buf, size_t size, UINT16 timestamp,
824 UINT32 audioTimeStamp)
825{
826 UINT error = CHANNEL_RC_OK;
827
828 WINPR_ASSERT(context);
829 WINPR_ASSERT(context->priv);
830
831 if (context->clientVersion < CHANNEL_VERSION_WIN_8)
832 return ERROR_INTERNAL_ERROR;
833
834 EnterCriticalSection(&context->priv->lock);
835
836 error =
837 rdpsnd_server_send_wave2_pdu(context, formatNo, buf, size, TRUE, timestamp, audioTimeStamp);
838
839 LeaveCriticalSection(&context->priv->lock);
840
841 return error;
842}
843
849static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, UINT16 left, UINT16 right)
850{
851 BOOL status = 0;
852 ULONG written = 0;
853 wStream* s = rdpsnd_server_get_buffer(context);
854
855 if (!Stream_EnsureRemainingCapacity(s, 8))
856 return ERROR_NOT_ENOUGH_MEMORY;
857
858 Stream_Write_UINT8(s, SNDC_SETVOLUME);
859 Stream_Write_UINT8(s, 0);
860 Stream_Write_UINT16(s, 4); /* Payload length */
861 Stream_Write_UINT16(s, left);
862 Stream_Write_UINT16(s, right);
863
864 const size_t len = Stream_GetPosition(s);
865 WINPR_ASSERT(len <= UINT32_MAX);
866 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
867 (ULONG)len, &written);
868 Stream_ResetPosition(s);
869 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
870}
871
877static UINT rdpsnd_server_close(RdpsndServerContext* context)
878{
879 BOOL status = 0;
880 ULONG written = 0;
881 UINT error = CHANNEL_RC_OK;
882 wStream* s = rdpsnd_server_get_buffer(context);
883
884 EnterCriticalSection(&context->priv->lock);
885
886 if (context->priv->out_pending_frames > 0)
887 {
888 if (context->selected_client_format >= context->num_client_formats)
889 {
890 WLog_ERR(TAG, "Pending audio frame exists while no format selected.");
891 error = ERROR_INVALID_DATA;
892 }
893 else if ((error = rdpsnd_server_send_audio_pdu(context, 0)))
894 {
895 WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error);
896 }
897 }
898
899 LeaveCriticalSection(&context->priv->lock);
900
901 if (error)
902 return error;
903
904 context->selected_client_format = 0xFFFF;
905
906 if (!Stream_EnsureRemainingCapacity(s, 4))
907 return ERROR_OUTOFMEMORY;
908
909 Stream_Write_UINT8(s, SNDC_CLOSE);
910 Stream_Write_UINT8(s, 0);
911 Stream_Seek_UINT16(s);
912 const size_t pos = Stream_GetPosition(s);
913 WINPR_ASSERT(pos >= 4);
914 if (!Stream_SetPosition(s, 2))
915 return ERROR_INVALID_DATA;
916 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, pos - 4));
917 if (!Stream_SetPosition(s, pos))
918 return ERROR_INVALID_DATA;
919
920 const size_t len = Stream_GetPosition(s);
921 WINPR_ASSERT(len <= UINT32_MAX);
922 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
923 (UINT32)len, &written);
924 Stream_ResetPosition(s);
925 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
926}
927
933static UINT rdpsnd_server_start(RdpsndServerContext* context)
934{
935 void* buffer = nullptr;
936 DWORD bytesReturned = 0;
937 RdpsndServerPrivate* priv = nullptr;
938 UINT error = ERROR_INTERNAL_ERROR;
939 PULONG pSessionId = nullptr;
940
941 WINPR_ASSERT(context);
942 WINPR_ASSERT(context->priv);
943
944 priv = context->priv;
945 priv->SessionId = WTS_CURRENT_SESSION;
946
947 if (context->use_dynamic_virtual_channel)
948 {
949 UINT32 channelId = 0;
950 BOOL status = TRUE;
951
952 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
953 (LPSTR*)&pSessionId, &bytesReturned))
954 {
955 priv->SessionId = (DWORD)*pSessionId;
956 WTSFreeMemory(pSessionId);
957 priv->ChannelHandle = WTSVirtualChannelOpenEx(priv->SessionId, RDPSND_DVC_CHANNEL_NAME,
958 WTS_CHANNEL_OPTION_DYNAMIC);
959 if (!priv->ChannelHandle)
960 {
961 WLog_ERR(TAG, "Open audio dynamic virtual channel (%s) failed!",
962 RDPSND_DVC_CHANNEL_NAME);
963 return ERROR_INTERNAL_ERROR;
964 }
965
966 channelId = WTSChannelGetIdByHandle(priv->ChannelHandle);
967
968 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
969 if (!status)
970 {
971 WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
972 goto out_close;
973 }
974 }
975 else
976 {
977 WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
978 return ERROR_INTERNAL_ERROR;
979 }
980 }
981 else
982 {
983 priv->ChannelHandle =
984 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPSND_CHANNEL_NAME);
985 if (!priv->ChannelHandle)
986 {
987 WLog_ERR(TAG, "Open audio static virtual channel (rdpsnd) failed!");
988 return ERROR_INTERNAL_ERROR;
989 }
990 }
991
992 if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
993 &bytesReturned) ||
994 (bytesReturned != sizeof(HANDLE)))
995 {
996 WLog_ERR(TAG,
997 "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned "
998 "size(%" PRIu32 ")",
999 bytesReturned);
1000
1001 if (buffer)
1002 WTSFreeMemory(buffer);
1003
1004 goto out_close;
1005 }
1006
1007 priv->channelEvent = *(HANDLE*)buffer;
1008 WTSFreeMemory(buffer);
1009 priv->rdpsnd_pdu = Stream_New(nullptr, 4096);
1010
1011 if (!priv->rdpsnd_pdu)
1012 {
1013 WLog_ERR(TAG, "Stream_New failed!");
1014 error = CHANNEL_RC_NO_MEMORY;
1015 goto out_close;
1016 }
1017
1018 if (!InitializeCriticalSectionEx(&context->priv->lock, 0, 0))
1019 {
1020 WLog_ERR(TAG, "InitializeCriticalSectionEx failed!");
1021 goto out_pdu;
1022 }
1023
1024 if ((error = rdpsnd_server_send_formats(context)))
1025 {
1026 WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %" PRIu32 "", error);
1027 goto out_lock;
1028 }
1029
1030 if (priv->ownThread)
1031 {
1032 context->priv->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
1033
1034 if (!context->priv->StopEvent)
1035 {
1036 WLog_ERR(TAG, "CreateEvent failed!");
1037 goto out_lock;
1038 }
1039
1040 context->priv->Thread =
1041 CreateThread(nullptr, 0, rdpsnd_server_thread, (void*)context, 0, nullptr);
1042
1043 if (!context->priv->Thread)
1044 {
1045 WLog_ERR(TAG, "CreateThread failed!");
1046 goto out_stopEvent;
1047 }
1048 }
1049
1050 return CHANNEL_RC_OK;
1051out_stopEvent:
1052 (void)CloseHandle(context->priv->StopEvent);
1053 context->priv->StopEvent = nullptr;
1054out_lock:
1055 DeleteCriticalSection(&context->priv->lock);
1056out_pdu:
1057 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1058 context->priv->rdpsnd_pdu = nullptr;
1059out_close:
1060 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1061 context->priv->ChannelHandle = nullptr;
1062 return error;
1063}
1064
1070static UINT rdpsnd_server_stop(RdpsndServerContext* context)
1071{
1072 UINT error = CHANNEL_RC_OK;
1073
1074 WINPR_ASSERT(context);
1075 WINPR_ASSERT(context->priv);
1076
1077 if (!context->priv->StopEvent)
1078 return error;
1079
1080 if (context->priv->ownThread)
1081 {
1082 if (context->priv->StopEvent)
1083 {
1084 (void)SetEvent(context->priv->StopEvent);
1085
1086 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
1087 {
1088 error = GetLastError();
1089 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
1090 return error;
1091 }
1092
1093 (void)CloseHandle(context->priv->Thread);
1094 (void)CloseHandle(context->priv->StopEvent);
1095 context->priv->Thread = nullptr;
1096 context->priv->StopEvent = nullptr;
1097 }
1098 }
1099
1100 DeleteCriticalSection(&context->priv->lock);
1101
1102 if (context->priv->rdpsnd_pdu)
1103 {
1104 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1105 context->priv->rdpsnd_pdu = nullptr;
1106 }
1107
1108 if (context->priv->ChannelHandle)
1109 {
1110 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1111 context->priv->ChannelHandle = nullptr;
1112 }
1113
1114 return error;
1115}
1116
1117RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
1118{
1119 RdpsndServerPrivate* priv = nullptr;
1120 RdpsndServerContext* context = (RdpsndServerContext*)calloc(1, sizeof(RdpsndServerContext));
1121
1122 if (!context)
1123 goto fail;
1124
1125 context->vcm = vcm;
1126 context->Start = rdpsnd_server_start;
1127 context->Stop = rdpsnd_server_stop;
1128 context->selected_client_format = 0xFFFF;
1129 context->Initialize = rdpsnd_server_initialize;
1130 context->SendFormats = rdpsnd_server_send_formats;
1131 context->SelectFormat = rdpsnd_server_select_format;
1132 context->Training = rdpsnd_server_training;
1133 context->SendSamples = rdpsnd_server_send_samples;
1134 context->SendSamples2 = rdpsnd_server_send_samples2;
1135 context->SetVolume = rdpsnd_server_set_volume;
1136 context->Close = rdpsnd_server_close;
1137 context->priv = priv = (RdpsndServerPrivate*)calloc(1, sizeof(RdpsndServerPrivate));
1138
1139 if (!priv)
1140 {
1141 WLog_ERR(TAG, "calloc failed!");
1142 goto fail;
1143 }
1144
1145 priv->dsp_context = freerdp_dsp_context_new(TRUE);
1146
1147 if (!priv->dsp_context)
1148 {
1149 WLog_ERR(TAG, "freerdp_dsp_context_new failed!");
1150 goto fail;
1151 }
1152
1153 priv->input_stream = Stream_New(nullptr, 4);
1154
1155 if (!priv->input_stream)
1156 {
1157 WLog_ERR(TAG, "Stream_New failed!");
1158 goto fail;
1159 }
1160
1161 priv->expectedBytes = 4;
1162 priv->waitingHeader = TRUE;
1163 priv->ownThread = TRUE;
1164 return context;
1165fail:
1166 WINPR_PRAGMA_DIAG_PUSH
1167 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1168 rdpsnd_server_context_free(context);
1169 WINPR_PRAGMA_DIAG_POP
1170 return nullptr;
1171}
1172
1173void rdpsnd_server_context_reset(RdpsndServerContext* context)
1174{
1175 WINPR_ASSERT(context);
1176 WINPR_ASSERT(context->priv);
1177
1178 context->priv->expectedBytes = 4;
1179 context->priv->waitingHeader = TRUE;
1180 Stream_ResetPosition(context->priv->input_stream);
1181}
1182
1183void rdpsnd_server_context_free(RdpsndServerContext* context)
1184{
1185 if (!context)
1186 return;
1187
1188 if (context->priv)
1189 {
1190 rdpsnd_server_stop(context);
1191
1192 free(context->priv->out_buffer);
1193
1194 if (context->priv->dsp_context)
1195 freerdp_dsp_context_free(context->priv->dsp_context);
1196
1197 if (context->priv->input_stream)
1198 Stream_Free(context->priv->input_stream, TRUE);
1199 }
1200
1201 free(context->server_formats);
1202 rdpsnd_server_client_format_free(context);
1203 free(context->priv);
1204 free(context);
1205}
1206
1207HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context)
1208{
1209 WINPR_ASSERT(context);
1210 WINPR_ASSERT(context->priv);
1211
1212 return context->priv->channelEvent;
1213}
1214
1215/*
1216 * Handle rpdsnd messages - server side
1217 *
1218 * @param Server side context
1219 *
1220 * @return 0 on success
1221 * ERROR_NO_DATA if no data could be read this time
1222 * otherwise error
1223 */
1229UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
1230{
1231 DWORD bytesReturned = 0;
1232 UINT ret = CHANNEL_RC_OK;
1233 RdpsndServerPrivate* priv = nullptr;
1234 wStream* s = nullptr;
1235
1236 WINPR_ASSERT(context);
1237 WINPR_ASSERT(context->priv);
1238
1239 priv = context->priv;
1240 s = priv->input_stream;
1241
1242 if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
1243 &bytesReturned))
1244 {
1245 if (GetLastError() == ERROR_NO_DATA)
1246 return ERROR_NO_DATA;
1247
1248 WLog_ERR(TAG, "channel connection closed");
1249 return ERROR_INTERNAL_ERROR;
1250 }
1251
1252 priv->expectedBytes -= bytesReturned;
1253 Stream_Seek(s, bytesReturned);
1254
1255 if (priv->expectedBytes)
1256 return CHANNEL_RC_OK;
1257
1258 Stream_SealLength(s);
1259 Stream_ResetPosition(s);
1260
1261 if (priv->waitingHeader)
1262 {
1263 /* header case */
1264 Stream_Read_UINT8(s, priv->msgType);
1265 Stream_Seek_UINT8(s); /* bPad */
1266 Stream_Read_UINT16(s, priv->expectedBytes);
1267 priv->waitingHeader = FALSE;
1268 Stream_ResetPosition(s);
1269
1270 if (priv->expectedBytes)
1271 {
1272 if (!Stream_EnsureCapacity(s, priv->expectedBytes))
1273 {
1274 WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
1275 return CHANNEL_RC_NO_MEMORY;
1276 }
1277
1278 return CHANNEL_RC_OK;
1279 }
1280 }
1281
1282 /* when here we have the header + the body */
1283#ifdef WITH_DEBUG_SND
1284 WLog_DBG(TAG, "message type %" PRIu8 "", priv->msgType);
1285#endif
1286 priv->expectedBytes = 4;
1287 priv->waitingHeader = TRUE;
1288
1289 switch (priv->msgType)
1290 {
1291 case SNDC_WAVECONFIRM:
1292 ret = rdpsnd_server_recv_waveconfirm(context, s);
1293 break;
1294
1295 case SNDC_TRAINING:
1296 ret = rdpsnd_server_recv_trainingconfirm(context, s);
1297 break;
1298
1299 case SNDC_FORMATS:
1300 ret = rdpsnd_server_recv_formats(context, s);
1301
1302 if ((ret == CHANNEL_RC_OK) && (context->clientVersion < CHANNEL_VERSION_WIN_7))
1303 IFCALL(context->Activated, context);
1304
1305 break;
1306
1307 case SNDC_QUALITYMODE:
1308 ret = rdpsnd_server_recv_quality_mode(context, s);
1309
1310 if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7))
1311 IFCALL(context->Activated, context);
1312
1313 break;
1314
1315 default:
1316 WLog_ERR(TAG, "UNKNOWN MESSAGE TYPE!! (0x%02" PRIX8 ")", priv->msgType);
1317 ret = ERROR_INVALID_DATA;
1318 break;
1319 }
1320
1321 Stream_ResetPosition(s);
1322 return ret;
1323}