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