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