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