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