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