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
525static BOOL rdpsnd_server_align_wave_pdu(wStream* s, UINT32 alignment)
526{
527 size_t size = 0;
528 Stream_SealLength(s);
529 size = Stream_Length(s);
530
531 if ((size % alignment) != 0)
532 {
533 size_t offset = alignment - size % alignment;
534
535 if (!Stream_EnsureRemainingCapacity(s, offset))
536 return FALSE;
537
538 Stream_Zero(s, offset);
539 }
540
541 Stream_SealLength(s);
542 return TRUE;
543}
544
551static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
552{
553 ULONG written = 0;
554 UINT error = CHANNEL_RC_OK;
555 wStream* s = rdpsnd_server_get_buffer(context);
556
557 if (context->selected_client_format > context->num_client_formats)
558 return ERROR_INTERNAL_ERROR;
559
560 WINPR_ASSERT(context->client_formats);
561
562 const AUDIO_FORMAT* format = &context->client_formats[context->selected_client_format];
563 /* WaveInfo PDU */
564 Stream_ResetPosition(s);
565
566 if (!Stream_EnsureRemainingCapacity(s, 16))
567 return ERROR_OUTOFMEMORY;
568
569 Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */
570 Stream_Write_UINT8(s, 0); /* bPad */
571 Stream_Write_UINT16(s, 0); /* BodySize */
572 Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */
573 Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */
574 Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
575 Stream_Seek(s, 3); /* bPad */
576 const size_t start = Stream_GetPosition(s);
577 const BYTE* src = context->priv->out_buffer;
578 const size_t length =
579 1ull * context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
580
581 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s))
582 return ERROR_INTERNAL_ERROR;
583
584 /* Set stream size */
585 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
586 return ERROR_INTERNAL_ERROR;
587
588 const size_t end = Stream_GetPosition(s);
589 const size_t pos = end - start + 8ULL;
590 if (pos > UINT16_MAX)
591 return ERROR_INTERNAL_ERROR;
592 if (!Stream_SetPosition(s, 2))
593 return ERROR_INTERNAL_ERROR;
594 Stream_Write_UINT16(s, (UINT16)pos);
595 if (!Stream_SetPosition(s, end))
596 return ERROR_INTERNAL_ERROR;
597
598 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
599 (UINT32)(start + 4), &written))
600 {
601 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
602 error = ERROR_INTERNAL_ERROR;
603 }
604
605 if (error != CHANNEL_RC_OK)
606 {
607 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
608 error = ERROR_INTERNAL_ERROR;
609 goto out;
610 }
611
612 if (!Stream_SetPosition(s, start))
613 {
614 error = ERROR_INTERNAL_ERROR;
615 goto out;
616 }
617 Stream_Write_UINT32(s, 0); /* bPad */
618 if (!Stream_SetPosition(s, start))
619 {
620 error = ERROR_INTERNAL_ERROR;
621 goto out;
622 }
623
624 WINPR_ASSERT((end - start) <= UINT32_MAX);
625 if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Pointer(s),
626 (UINT32)(end - start), &written))
627 {
628 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
629 error = ERROR_INTERNAL_ERROR;
630 }
631
632 context->block_no = (context->block_no + 1) % 256;
633
634out:
635 Stream_ResetPosition(s);
636 context->priv->out_pending_frames = 0;
637 return error;
638}
639
646static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 formatNo,
647 const BYTE* data, size_t size, BOOL encoded,
648 UINT16 timestamp, UINT32 audioTimeStamp)
649{
650 ULONG written = 0;
651 UINT error = CHANNEL_RC_OK;
652 wStream* s = rdpsnd_server_get_buffer(context);
653
654 if (!Stream_EnsureRemainingCapacity(s, 16))
655 {
656 error = ERROR_INTERNAL_ERROR;
657 goto out;
658 }
659
660 /* Wave2 PDU */
661 Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */
662 Stream_Write_UINT8(s, 0); /* bPad */
663 Stream_Write_UINT16(s, 0); /* BodySize */
664 Stream_Write_UINT16(s, timestamp); /* wTimeStamp */
665 Stream_Write_UINT16(s, formatNo); /* wFormatNo */
666 Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
667 Stream_Write_UINT8(s, 0); /* bPad */
668 Stream_Write_UINT8(s, 0); /* bPad */
669 Stream_Write_UINT8(s, 0); /* bPad */
670 Stream_Write_UINT32(s, audioTimeStamp); /* dwAudioTimeStamp */
671
672 if (encoded)
673 {
674 if (!Stream_EnsureRemainingCapacity(s, size))
675 {
676 error = ERROR_INTERNAL_ERROR;
677 goto out;
678 }
679
680 Stream_Write(s, data, size);
681 }
682 else
683 {
684 if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, data, size, s))
685 {
686 error = ERROR_INTERNAL_ERROR;
687 goto out;
688 }
689
690 const AUDIO_FORMAT* format = &context->client_formats[formatNo];
691 if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
692 {
693 error = ERROR_INTERNAL_ERROR;
694 goto out;
695 }
696 }
697
698 {
699 const size_t end = Stream_GetPosition(s);
700 if (end > UINT16_MAX + 4)
701 {
702 error = ERROR_INTERNAL_ERROR;
703 goto out;
704 }
705
706 if (!Stream_SetPosition(s, 2))
707 {
708 error = ERROR_INTERNAL_ERROR;
709 goto out;
710 }
711 Stream_Write_UINT16(s, (UINT16)(end - 4));
712
713 const BOOL status = WTSVirtualChannelWrite(context->priv->ChannelHandle,
714 Stream_BufferAs(s, char), (UINT32)end, &written);
715
716 if (!status || (end != written))
717 {
718 WLog_ERR(TAG,
719 "WTSVirtualChannelWrite failed! [stream length=%" PRIuz " - written=%" PRIu32,
720 end, written);
721 error = ERROR_INTERNAL_ERROR;
722 }
723 }
724
725 context->block_no = (context->block_no + 1) % 256;
726
727out:
728 Stream_ResetPosition(s);
729 context->priv->out_pending_frames = 0;
730 return error;
731}
732
733/* Wrapper function to send WAVE or WAVE2 PDU depending on client connected */
734static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
735{
736 const BYTE* src = nullptr;
737 size_t length = 0;
738
739 WINPR_ASSERT(context);
740 WINPR_ASSERT(context->priv);
741
742 if (context->selected_client_format >= context->num_client_formats)
743 return ERROR_INTERNAL_ERROR;
744
745 src = context->priv->out_buffer;
746 length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
747
748 if (context->clientVersion >= CHANNEL_VERSION_WIN_8)
749 return rdpsnd_server_send_wave2_pdu(context, context->selected_client_format, src, length,
750 FALSE, wTimestamp, wTimestamp);
751 else
752 return rdpsnd_server_send_wave_pdu(context, wTimestamp);
753}
754
760static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf,
761 size_t nframes, UINT16 wTimestamp)
762{
763 UINT error = CHANNEL_RC_OK;
764
765 WINPR_ASSERT(context);
766 WINPR_ASSERT(context->priv);
767
768 EnterCriticalSection(&context->priv->lock);
769
770 if (context->selected_client_format >= context->num_client_formats)
771 {
772 /* It's possible while format negotiation has not been done */
773 WLog_WARN(TAG, "Drop samples because client format has not been negotiated.");
774 error = ERROR_NOT_READY;
775 goto out;
776 }
777
778 while (nframes > 0)
779 {
780 const size_t cframes =
781 MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames);
782 size_t cframesize = cframes * context->priv->src_bytes_per_frame;
783 CopyMemory(context->priv->out_buffer +
784 (context->priv->out_pending_frames * context->priv->src_bytes_per_frame),
785 buf, cframesize);
786 buf = (const BYTE*)buf + cframesize;
787 nframes -= cframes;
788 context->priv->out_pending_frames += cframes;
789
790 if (context->priv->out_pending_frames >= context->priv->out_frames)
791 {
792 if ((error = rdpsnd_server_send_audio_pdu(context, wTimestamp)))
793 {
794 WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error);
795 break;
796 }
797 }
798 }
799
800out:
801 LeaveCriticalSection(&context->priv->lock);
802 return error;
803}
804
810static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 formatNo,
811 const void* buf, size_t size, UINT16 timestamp,
812 UINT32 audioTimeStamp)
813{
814 UINT error = CHANNEL_RC_OK;
815
816 WINPR_ASSERT(context);
817 WINPR_ASSERT(context->priv);
818
819 if (context->clientVersion < CHANNEL_VERSION_WIN_8)
820 return ERROR_INTERNAL_ERROR;
821
822 EnterCriticalSection(&context->priv->lock);
823
824 error =
825 rdpsnd_server_send_wave2_pdu(context, formatNo, buf, size, TRUE, timestamp, audioTimeStamp);
826
827 LeaveCriticalSection(&context->priv->lock);
828
829 return error;
830}
831
837static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, UINT16 left, UINT16 right)
838{
839 BOOL status = 0;
840 ULONG written = 0;
841 wStream* s = rdpsnd_server_get_buffer(context);
842
843 if (!Stream_EnsureRemainingCapacity(s, 8))
844 return ERROR_NOT_ENOUGH_MEMORY;
845
846 Stream_Write_UINT8(s, SNDC_SETVOLUME);
847 Stream_Write_UINT8(s, 0);
848 Stream_Write_UINT16(s, 4); /* Payload length */
849 Stream_Write_UINT16(s, left);
850 Stream_Write_UINT16(s, right);
851
852 const size_t len = Stream_GetPosition(s);
853 WINPR_ASSERT(len <= UINT32_MAX);
854 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
855 (ULONG)len, &written);
856 Stream_ResetPosition(s);
857 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
858}
859
865static UINT rdpsnd_server_close(RdpsndServerContext* context)
866{
867 BOOL status = 0;
868 ULONG written = 0;
869 UINT error = CHANNEL_RC_OK;
870 wStream* s = rdpsnd_server_get_buffer(context);
871
872 EnterCriticalSection(&context->priv->lock);
873
874 if (context->priv->out_pending_frames > 0)
875 {
876 if (context->selected_client_format >= context->num_client_formats)
877 {
878 WLog_ERR(TAG, "Pending audio frame exists while no format selected.");
879 error = ERROR_INVALID_DATA;
880 }
881 else if ((error = rdpsnd_server_send_audio_pdu(context, 0)))
882 {
883 WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error);
884 }
885 }
886
887 LeaveCriticalSection(&context->priv->lock);
888
889 if (error)
890 return error;
891
892 context->selected_client_format = 0xFFFF;
893
894 if (!Stream_EnsureRemainingCapacity(s, 4))
895 return ERROR_OUTOFMEMORY;
896
897 Stream_Write_UINT8(s, SNDC_CLOSE);
898 Stream_Write_UINT8(s, 0);
899 Stream_Seek_UINT16(s);
900 const size_t pos = Stream_GetPosition(s);
901 WINPR_ASSERT(pos >= 4);
902 if (!Stream_SetPosition(s, 2))
903 return ERROR_INVALID_DATA;
904 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, pos - 4));
905 if (!Stream_SetPosition(s, pos))
906 return ERROR_INVALID_DATA;
907
908 const size_t len = Stream_GetPosition(s);
909 WINPR_ASSERT(len <= UINT32_MAX);
910 status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
911 (UINT32)len, &written);
912 Stream_ResetPosition(s);
913 return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
914}
915
921static UINT rdpsnd_server_start(RdpsndServerContext* context)
922{
923 void* buffer = nullptr;
924 DWORD bytesReturned = 0;
925 RdpsndServerPrivate* priv = nullptr;
926 UINT error = ERROR_INTERNAL_ERROR;
927 PULONG pSessionId = nullptr;
928
929 WINPR_ASSERT(context);
930 WINPR_ASSERT(context->priv);
931
932 priv = context->priv;
933 priv->SessionId = WTS_CURRENT_SESSION;
934
935 if (context->use_dynamic_virtual_channel)
936 {
937 UINT32 channelId = 0;
938 BOOL status = TRUE;
939
940 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
941 (LPSTR*)&pSessionId, &bytesReturned))
942 {
943 priv->SessionId = (DWORD)*pSessionId;
944 WTSFreeMemory(pSessionId);
945 priv->ChannelHandle = WTSVirtualChannelOpenEx(priv->SessionId, RDPSND_DVC_CHANNEL_NAME,
946 WTS_CHANNEL_OPTION_DYNAMIC);
947 if (!priv->ChannelHandle)
948 {
949 WLog_ERR(TAG, "Open audio dynamic virtual channel (%s) failed!",
950 RDPSND_DVC_CHANNEL_NAME);
951 return ERROR_INTERNAL_ERROR;
952 }
953
954 channelId = WTSChannelGetIdByHandle(priv->ChannelHandle);
955
956 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
957 if (!status)
958 {
959 WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
960 goto out_close;
961 }
962 }
963 else
964 {
965 WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
966 return ERROR_INTERNAL_ERROR;
967 }
968 }
969 else
970 {
971 priv->ChannelHandle =
972 WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPSND_CHANNEL_NAME);
973 if (!priv->ChannelHandle)
974 {
975 WLog_ERR(TAG, "Open audio static virtual channel (rdpsnd) failed!");
976 return ERROR_INTERNAL_ERROR;
977 }
978 }
979
980 if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
981 &bytesReturned) ||
982 (bytesReturned != sizeof(HANDLE)))
983 {
984 WLog_ERR(TAG,
985 "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned "
986 "size(%" PRIu32 ")",
987 bytesReturned);
988
989 if (buffer)
990 WTSFreeMemory(buffer);
991
992 goto out_close;
993 }
994
995 priv->channelEvent = *(HANDLE*)buffer;
996 WTSFreeMemory(buffer);
997 priv->rdpsnd_pdu = Stream_New(nullptr, 4096);
998
999 if (!priv->rdpsnd_pdu)
1000 {
1001 WLog_ERR(TAG, "Stream_New failed!");
1002 error = CHANNEL_RC_NO_MEMORY;
1003 goto out_close;
1004 }
1005
1006 if (!InitializeCriticalSectionEx(&context->priv->lock, 0, 0))
1007 {
1008 WLog_ERR(TAG, "InitializeCriticalSectionEx failed!");
1009 goto out_pdu;
1010 }
1011
1012 if ((error = rdpsnd_server_send_formats(context)))
1013 {
1014 WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %" PRIu32 "", error);
1015 goto out_lock;
1016 }
1017
1018 if (priv->ownThread)
1019 {
1020 context->priv->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
1021
1022 if (!context->priv->StopEvent)
1023 {
1024 WLog_ERR(TAG, "CreateEvent failed!");
1025 goto out_lock;
1026 }
1027
1028 context->priv->Thread =
1029 CreateThread(nullptr, 0, rdpsnd_server_thread, (void*)context, 0, nullptr);
1030
1031 if (!context->priv->Thread)
1032 {
1033 WLog_ERR(TAG, "CreateThread failed!");
1034 goto out_stopEvent;
1035 }
1036 }
1037
1038 return CHANNEL_RC_OK;
1039out_stopEvent:
1040 (void)CloseHandle(context->priv->StopEvent);
1041 context->priv->StopEvent = nullptr;
1042out_lock:
1043 DeleteCriticalSection(&context->priv->lock);
1044out_pdu:
1045 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1046 context->priv->rdpsnd_pdu = nullptr;
1047out_close:
1048 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1049 context->priv->ChannelHandle = nullptr;
1050 return error;
1051}
1052
1058static UINT rdpsnd_server_stop(RdpsndServerContext* context)
1059{
1060 UINT error = CHANNEL_RC_OK;
1061
1062 WINPR_ASSERT(context);
1063 WINPR_ASSERT(context->priv);
1064
1065 if (!context->priv->ChannelHandle)
1066 return error;
1067
1068 if (context->priv->ownThread)
1069 {
1070 if (context->priv->StopEvent)
1071 {
1072 (void)SetEvent(context->priv->StopEvent);
1073
1074 if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
1075 {
1076 error = GetLastError();
1077 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
1078 return error;
1079 }
1080
1081 (void)CloseHandle(context->priv->Thread);
1082 (void)CloseHandle(context->priv->StopEvent);
1083 context->priv->Thread = nullptr;
1084 context->priv->StopEvent = nullptr;
1085 }
1086 }
1087
1088 DeleteCriticalSection(&context->priv->lock);
1089
1090 if (context->priv->rdpsnd_pdu)
1091 {
1092 Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1093 context->priv->rdpsnd_pdu = nullptr;
1094 }
1095
1096 if (context->priv->ChannelHandle)
1097 {
1098 (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1099 context->priv->ChannelHandle = nullptr;
1100 }
1101
1102 return error;
1103}
1104
1105RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
1106{
1107 RdpsndServerPrivate* priv = nullptr;
1108 RdpsndServerContext* context = (RdpsndServerContext*)calloc(1, sizeof(RdpsndServerContext));
1109
1110 if (!context)
1111 goto fail;
1112
1113 context->vcm = vcm;
1114 context->Start = rdpsnd_server_start;
1115 context->Stop = rdpsnd_server_stop;
1116 context->selected_client_format = 0xFFFF;
1117 context->Initialize = rdpsnd_server_initialize;
1118 context->SendFormats = rdpsnd_server_send_formats;
1119 context->SelectFormat = rdpsnd_server_select_format;
1120 context->Training = rdpsnd_server_training;
1121 context->SendSamples = rdpsnd_server_send_samples;
1122 context->SendSamples2 = rdpsnd_server_send_samples2;
1123 context->SetVolume = rdpsnd_server_set_volume;
1124 context->Close = rdpsnd_server_close;
1125 context->priv = priv = (RdpsndServerPrivate*)calloc(1, sizeof(RdpsndServerPrivate));
1126
1127 if (!priv)
1128 {
1129 WLog_ERR(TAG, "calloc failed!");
1130 goto fail;
1131 }
1132
1133 priv->dsp_context = freerdp_dsp_context_new(TRUE);
1134
1135 if (!priv->dsp_context)
1136 {
1137 WLog_ERR(TAG, "freerdp_dsp_context_new failed!");
1138 goto fail;
1139 }
1140
1141 priv->input_stream = Stream_New(nullptr, 4);
1142
1143 if (!priv->input_stream)
1144 {
1145 WLog_ERR(TAG, "Stream_New failed!");
1146 goto fail;
1147 }
1148
1149 priv->expectedBytes = 4;
1150 priv->waitingHeader = TRUE;
1151 priv->ownThread = TRUE;
1152 return context;
1153fail:
1154 WINPR_PRAGMA_DIAG_PUSH
1155 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1156 rdpsnd_server_context_free(context);
1157 WINPR_PRAGMA_DIAG_POP
1158 return nullptr;
1159}
1160
1161void rdpsnd_server_context_reset(RdpsndServerContext* context)
1162{
1163 WINPR_ASSERT(context);
1164 WINPR_ASSERT(context->priv);
1165
1166 context->priv->expectedBytes = 4;
1167 context->priv->waitingHeader = TRUE;
1168 Stream_ResetPosition(context->priv->input_stream);
1169}
1170
1171void rdpsnd_server_context_free(RdpsndServerContext* context)
1172{
1173 if (!context)
1174 return;
1175
1176 if (context->priv)
1177 {
1178 rdpsnd_server_stop(context);
1179
1180 free(context->priv->out_buffer);
1181
1182 if (context->priv->dsp_context)
1183 freerdp_dsp_context_free(context->priv->dsp_context);
1184
1185 if (context->priv->input_stream)
1186 Stream_Free(context->priv->input_stream, TRUE);
1187 }
1188
1189 free(context->server_formats);
1190 rdpsnd_server_client_format_free(context);
1191 free(context->priv);
1192 free(context);
1193}
1194
1195HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context)
1196{
1197 WINPR_ASSERT(context);
1198 WINPR_ASSERT(context->priv);
1199
1200 return context->priv->channelEvent;
1201}
1202
1203/*
1204 * Handle rpdsnd messages - server side
1205 *
1206 * @param Server side context
1207 *
1208 * @return 0 on success
1209 * ERROR_NO_DATA if no data could be read this time
1210 * otherwise error
1211 */
1217UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
1218{
1219 DWORD bytesReturned = 0;
1220 UINT ret = CHANNEL_RC_OK;
1221 RdpsndServerPrivate* priv = nullptr;
1222 wStream* s = nullptr;
1223
1224 WINPR_ASSERT(context);
1225 WINPR_ASSERT(context->priv);
1226
1227 priv = context->priv;
1228 s = priv->input_stream;
1229
1230 if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
1231 &bytesReturned))
1232 {
1233 if (GetLastError() == ERROR_NO_DATA)
1234 return ERROR_NO_DATA;
1235
1236 WLog_ERR(TAG, "channel connection closed");
1237 return ERROR_INTERNAL_ERROR;
1238 }
1239
1240 priv->expectedBytes -= bytesReturned;
1241 Stream_Seek(s, bytesReturned);
1242
1243 if (priv->expectedBytes)
1244 return CHANNEL_RC_OK;
1245
1246 Stream_SealLength(s);
1247 Stream_ResetPosition(s);
1248
1249 if (priv->waitingHeader)
1250 {
1251 /* header case */
1252 Stream_Read_UINT8(s, priv->msgType);
1253 Stream_Seek_UINT8(s); /* bPad */
1254 Stream_Read_UINT16(s, priv->expectedBytes);
1255 priv->waitingHeader = FALSE;
1256 Stream_ResetPosition(s);
1257
1258 if (priv->expectedBytes)
1259 {
1260 if (!Stream_EnsureCapacity(s, priv->expectedBytes))
1261 {
1262 WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
1263 return CHANNEL_RC_NO_MEMORY;
1264 }
1265
1266 return CHANNEL_RC_OK;
1267 }
1268 }
1269
1270 /* when here we have the header + the body */
1271#ifdef WITH_DEBUG_SND
1272 WLog_DBG(TAG, "message type %" PRIu8 "", priv->msgType);
1273#endif
1274 priv->expectedBytes = 4;
1275 priv->waitingHeader = TRUE;
1276
1277 switch (priv->msgType)
1278 {
1279 case SNDC_WAVECONFIRM:
1280 ret = rdpsnd_server_recv_waveconfirm(context, s);
1281 break;
1282
1283 case SNDC_TRAINING:
1284 ret = rdpsnd_server_recv_trainingconfirm(context, s);
1285 break;
1286
1287 case SNDC_FORMATS:
1288 ret = rdpsnd_server_recv_formats(context, s);
1289
1290 if ((ret == CHANNEL_RC_OK) && (context->clientVersion < CHANNEL_VERSION_WIN_7))
1291 IFCALL(context->Activated, context);
1292
1293 break;
1294
1295 case SNDC_QUALITYMODE:
1296 ret = rdpsnd_server_recv_quality_mode(context, s);
1297
1298 if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7))
1299 IFCALL(context->Activated, context);
1300
1301 break;
1302
1303 default:
1304 WLog_ERR(TAG, "UNKNOWN MESSAGE TYPE!! (0x%02" PRIX8 ")", priv->msgType);
1305 ret = ERROR_INVALID_DATA;
1306 break;
1307 }
1308
1309 Stream_ResetPosition(s);
1310 return ret;
1311}