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