FreeRDP
Loading...
Searching...
No Matches
audin.c
1
23#include <freerdp/config.h>
24
25#include <winpr/crt.h>
26#include <winpr/assert.h>
27#include <winpr/synch.h>
28#include <winpr/thread.h>
29#include <winpr/stream.h>
30
31#include <freerdp/freerdp.h>
32#include <freerdp/server/server-common.h>
33#include <freerdp/server/audin.h>
34#include <freerdp/channels/log.h>
35
36#define AUDIN_TAG CHANNELS_TAG("audin.server")
37
38#define SNDIN_HEADER_SIZE 1
39
40typedef enum
41{
42 MSG_SNDIN_VERSION = 0x01,
43 MSG_SNDIN_FORMATS = 0x02,
44 MSG_SNDIN_OPEN = 0x03,
45 MSG_SNDIN_OPEN_REPLY = 0x04,
46 MSG_SNDIN_DATA_INCOMING = 0x05,
47 MSG_SNDIN_DATA = 0x06,
48 MSG_SNDIN_FORMATCHANGE = 0x07,
49} MSG_SNDIN;
50
51typedef struct
52{
53 audin_server_context context;
54
55 HANDLE stopEvent;
56
57 HANDLE thread;
58 void* audin_channel;
59
60 DWORD SessionId;
61
62 AUDIO_FORMAT* audin_server_formats;
63 UINT32 audin_n_server_formats;
64 AUDIO_FORMAT* audin_negotiated_format;
65 UINT32 audin_client_format_idx;
66 wLog* log;
67} audin_server;
68
69static UINT audin_server_recv_version(audin_server_context* context, wStream* s,
70 const SNDIN_PDU* header)
71{
72 audin_server* audin = (audin_server*)context;
73 SNDIN_VERSION pdu = { 0 };
74 UINT error = CHANNEL_RC_OK;
75
76 WINPR_ASSERT(context);
77 WINPR_ASSERT(header);
78
79 pdu.Header = *header;
80
81 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4))
82 return ERROR_NO_DATA;
83
84 Stream_Read_UINT32(s, pdu.Version);
85
86 IFCALLRET(context->ReceiveVersion, error, context, &pdu);
87 if (error)
88 WLog_Print(audin->log, WLOG_ERROR, "context->ReceiveVersion failed with error %" PRIu32 "",
89 error);
90
91 return error;
92}
93
94static UINT audin_server_recv_formats(audin_server_context* context, wStream* s,
95 const SNDIN_PDU* header)
96{
97 audin_server* audin = (audin_server*)context;
98 SNDIN_FORMATS pdu = { 0 };
99 UINT error = CHANNEL_RC_OK;
100
101 WINPR_ASSERT(context);
102 WINPR_ASSERT(header);
103
104 pdu.Header = *header;
105
106 /* Implementations MUST, at a minimum, support WAVE_FORMAT_PCM (0x0001) */
107 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4 + 4 + 18))
108 return ERROR_NO_DATA;
109
110 Stream_Read_UINT32(s, pdu.NumFormats);
111 Stream_Read_UINT32(s, pdu.cbSizeFormatsPacket);
112
113 if (pdu.NumFormats == 0)
114 {
115 WLog_Print(audin->log, WLOG_ERROR, "Sound Formats PDU contains no formats");
116 return ERROR_INVALID_DATA;
117 }
118
119 pdu.SoundFormats = audio_formats_new(pdu.NumFormats);
120 if (!pdu.SoundFormats)
121 {
122 WLog_Print(audin->log, WLOG_ERROR, "Failed to allocate %u SoundFormats", pdu.NumFormats);
123 return ERROR_NOT_ENOUGH_MEMORY;
124 }
125
126 for (UINT32 i = 0; i < pdu.NumFormats; ++i)
127 {
128 AUDIO_FORMAT* format = &pdu.SoundFormats[i];
129
130 if (!audio_format_read(s, format))
131 {
132 WLog_Print(audin->log, WLOG_ERROR, "Failed to read audio format");
133 audio_formats_free(pdu.SoundFormats, i + i);
134 return ERROR_INVALID_DATA;
135 }
136
137 audio_format_print(audin->log, WLOG_DEBUG, format);
138 }
139
140 if (pdu.cbSizeFormatsPacket != Stream_GetPosition(s))
141 {
142 WLog_Print(audin->log, WLOG_WARN,
143 "cbSizeFormatsPacket is invalid! Expected: %u Got: %zu. Fixing size",
144 pdu.cbSizeFormatsPacket, Stream_GetPosition(s));
145 const size_t pos = Stream_GetPosition(s);
146 if (pos > UINT32_MAX)
147 {
148 WLog_Print(audin->log, WLOG_ERROR, "Stream too long, %" PRIuz " exceeds UINT32_MAX",
149 pos);
150 error = ERROR_INVALID_PARAMETER;
151 goto fail;
152 }
153 pdu.cbSizeFormatsPacket = (UINT32)pos;
154 }
155
156 pdu.ExtraDataSize = Stream_GetRemainingLength(s);
157
158 IFCALLRET(context->ReceiveFormats, error, context, &pdu);
159 if (error)
160 WLog_Print(audin->log, WLOG_ERROR, "context->ReceiveFormats failed with error %" PRIu32 "",
161 error);
162
163fail:
164 audio_formats_free(pdu.SoundFormats, pdu.NumFormats);
165
166 return error;
167}
168
169static UINT audin_server_recv_open_reply(audin_server_context* context, wStream* s,
170 const SNDIN_PDU* header)
171{
172 audin_server* audin = (audin_server*)context;
173 SNDIN_OPEN_REPLY pdu = { 0 };
174 UINT error = CHANNEL_RC_OK;
175
176 WINPR_ASSERT(context);
177 WINPR_ASSERT(header);
178
179 pdu.Header = *header;
180
181 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4))
182 return ERROR_NO_DATA;
183
184 Stream_Read_UINT32(s, pdu.Result);
185
186 IFCALLRET(context->OpenReply, error, context, &pdu);
187 if (error)
188 WLog_Print(audin->log, WLOG_ERROR, "context->OpenReply failed with error %" PRIu32 "",
189 error);
190
191 return error;
192}
193
194static UINT audin_server_recv_data_incoming(audin_server_context* context,
195 WINPR_ATTR_UNUSED wStream* s, const SNDIN_PDU* header)
196{
197 audin_server* audin = (audin_server*)context;
198 SNDIN_DATA_INCOMING pdu = { 0 };
199 UINT error = CHANNEL_RC_OK;
200
201 WINPR_ASSERT(context);
202 WINPR_ASSERT(header);
203
204 pdu.Header = *header;
205
206 IFCALLRET(context->IncomingData, error, context, &pdu);
207 if (error)
208 WLog_Print(audin->log, WLOG_ERROR, "context->IncomingData failed with error %" PRIu32 "",
209 error);
210
211 return error;
212}
213
214static UINT audin_server_recv_data(audin_server_context* context, wStream* s,
215 const SNDIN_PDU* header)
216{
217 audin_server* audin = (audin_server*)context;
218 SNDIN_DATA pdu = { 0 };
219 wStream dataBuffer = { 0 };
220 UINT error = CHANNEL_RC_OK;
221
222 WINPR_ASSERT(context);
223 WINPR_ASSERT(header);
224
225 pdu.Header = *header;
226
227 pdu.Data = Stream_StaticInit(&dataBuffer, Stream_Pointer(s), Stream_GetRemainingLength(s));
228
229 IFCALLRET(context->Data, error, context, &pdu);
230 if (error)
231 WLog_Print(audin->log, WLOG_ERROR, "context->Data failed with error %" PRIu32 "", error);
232
233 return error;
234}
235
236static UINT audin_server_recv_format_change(audin_server_context* context, wStream* s,
237 const SNDIN_PDU* header)
238{
239 audin_server* audin = (audin_server*)context;
240 SNDIN_FORMATCHANGE pdu = { 0 };
241 UINT error = CHANNEL_RC_OK;
242
243 WINPR_ASSERT(context);
244 WINPR_ASSERT(header);
245
246 pdu.Header = *header;
247
248 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4))
249 return ERROR_NO_DATA;
250
251 Stream_Read_UINT32(s, pdu.NewFormat);
252
253 IFCALLRET(context->ReceiveFormatChange, error, context, &pdu);
254 if (error)
255 WLog_Print(audin->log, WLOG_ERROR,
256 "context->ReceiveFormatChange failed with error %" PRIu32 "", error);
257
258 return error;
259}
260
261static DWORD WINAPI audin_server_thread_func(LPVOID arg)
262{
263 wStream* s = NULL;
264 void* buffer = NULL;
265 DWORD nCount = 0;
266 HANDLE events[8] = { 0 };
267 BOOL ready = FALSE;
268 HANDLE ChannelEvent = NULL;
269 DWORD BytesReturned = 0;
270 audin_server* audin = (audin_server*)arg;
271 UINT error = CHANNEL_RC_OK;
272 DWORD status = ERROR_INTERNAL_ERROR;
273
274 WINPR_ASSERT(audin);
275
276 if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualEventHandle, &buffer,
277 &BytesReturned) == TRUE)
278 {
279 if (BytesReturned == sizeof(HANDLE))
280 ChannelEvent = *(HANDLE*)buffer;
281
282 WTSFreeMemory(buffer);
283 }
284 else
285 {
286 WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelQuery failed");
287 error = ERROR_INTERNAL_ERROR;
288 goto out;
289 }
290
291 nCount = 0;
292 events[nCount++] = audin->stopEvent;
293 events[nCount++] = ChannelEvent;
294
295 /* Wait for the client to confirm that the Audio Input dynamic channel is ready */
296
297 while (1)
298 {
299 if ((status = WaitForMultipleObjects(nCount, events, FALSE, 100)) == WAIT_OBJECT_0)
300 goto out;
301
302 if (status == WAIT_FAILED)
303 {
304 error = GetLastError();
305 WLog_Print(audin->log, WLOG_ERROR,
306 "WaitForMultipleObjects failed with error %" PRIu32 "", error);
307 goto out;
308 }
309 if (status == WAIT_OBJECT_0)
310 goto out;
311
312 if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer,
313 &BytesReturned) == FALSE)
314 {
315 WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelQuery failed");
316 error = ERROR_INTERNAL_ERROR;
317 goto out;
318 }
319
320 ready = *((BOOL*)buffer);
321 WTSFreeMemory(buffer);
322
323 if (ready)
324 break;
325 }
326
327 s = Stream_New(NULL, 4096);
328
329 if (!s)
330 {
331 WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
332 error = CHANNEL_RC_NO_MEMORY;
333 goto out;
334 }
335
336 if (ready)
337 {
338 SNDIN_VERSION version = { 0 };
339
340 version.Version = audin->context.serverVersion;
341
342 if ((error = audin->context.SendVersion(&audin->context, &version)))
343 {
344 WLog_Print(audin->log, WLOG_ERROR, "SendVersion failed with error %" PRIu32 "!", error);
345 goto out_capacity;
346 }
347 }
348
349 while (ready)
350 {
351 SNDIN_PDU header = { 0 };
352
353 if ((status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE)) == WAIT_OBJECT_0)
354 break;
355
356 if (status == WAIT_FAILED)
357 {
358 error = GetLastError();
359 WLog_Print(audin->log, WLOG_ERROR,
360 "WaitForMultipleObjects failed with error %" PRIu32 "", error);
361 break;
362 }
363 if (status == WAIT_OBJECT_0)
364 break;
365
366 Stream_SetPosition(s, 0);
367
368 if (!WTSVirtualChannelRead(audin->audin_channel, 0, NULL, 0, &BytesReturned))
369 {
370 WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
371 error = ERROR_INTERNAL_ERROR;
372 break;
373 }
374
375 if (BytesReturned < 1)
376 continue;
377
378 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
379 break;
380
381 WINPR_ASSERT(Stream_Capacity(s) <= UINT32_MAX);
382 if (WTSVirtualChannelRead(audin->audin_channel, 0, Stream_BufferAs(s, char),
383 (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
384 {
385 WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
386 error = ERROR_INTERNAL_ERROR;
387 break;
388 }
389
390 Stream_SetLength(s, BytesReturned);
391 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, SNDIN_HEADER_SIZE))
392 {
393 error = ERROR_INTERNAL_ERROR;
394 break;
395 }
396
397 Stream_Read_UINT8(s, header.MessageId);
398
399 switch (header.MessageId)
400 {
401 case MSG_SNDIN_VERSION:
402 error = audin_server_recv_version(&audin->context, s, &header);
403 break;
404 case MSG_SNDIN_FORMATS:
405 error = audin_server_recv_formats(&audin->context, s, &header);
406 break;
407 case MSG_SNDIN_OPEN_REPLY:
408 error = audin_server_recv_open_reply(&audin->context, s, &header);
409 break;
410 case MSG_SNDIN_DATA_INCOMING:
411 error = audin_server_recv_data_incoming(&audin->context, s, &header);
412 break;
413 case MSG_SNDIN_DATA:
414 error = audin_server_recv_data(&audin->context, s, &header);
415 break;
416 case MSG_SNDIN_FORMATCHANGE:
417 error = audin_server_recv_format_change(&audin->context, s, &header);
418 break;
419 default:
420 WLog_Print(audin->log, WLOG_ERROR,
421 "audin_server_thread_func: unknown or invalid MessageId %" PRIu8 "",
422 header.MessageId);
423 error = ERROR_INVALID_DATA;
424 break;
425 }
426 if (error)
427 break;
428 }
429
430out_capacity:
431 Stream_Free(s, TRUE);
432out:
433 (void)WTSVirtualChannelClose(audin->audin_channel);
434 audin->audin_channel = NULL;
435
436 if (error && audin->context.rdpcontext)
437 setChannelError(audin->context.rdpcontext, error,
438 "audin_server_thread_func reported an error");
439
440 ExitThread(error);
441 return error;
442}
443
444static BOOL audin_server_open(audin_server_context* context)
445{
446 audin_server* audin = (audin_server*)context;
447
448 WINPR_ASSERT(audin);
449 if (!audin->thread)
450 {
451 PULONG pSessionId = NULL;
452 DWORD BytesReturned = 0;
453 audin->SessionId = WTS_CURRENT_SESSION;
454 UINT32 channelId = 0;
455 BOOL status = TRUE;
456
457 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
458 (LPSTR*)&pSessionId, &BytesReturned))
459 {
460 audin->SessionId = (DWORD)*pSessionId;
461 WTSFreeMemory(pSessionId);
462 }
463
464 audin->audin_channel = WTSVirtualChannelOpenEx(audin->SessionId, AUDIN_DVC_CHANNEL_NAME,
465 WTS_CHANNEL_OPTION_DYNAMIC);
466
467 if (!audin->audin_channel)
468 {
469 WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelOpenEx failed!");
470 return FALSE;
471 }
472
473 channelId = WTSChannelGetIdByHandle(audin->audin_channel);
474
475 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
476 if (!status)
477 {
478 WLog_Print(audin->log, WLOG_ERROR, "context->ChannelIdAssigned failed!");
479 return FALSE;
480 }
481
482 if (!(audin->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
483 {
484 WLog_Print(audin->log, WLOG_ERROR, "CreateEvent failed!");
485 return FALSE;
486 }
487
488 if (!(audin->thread =
489 CreateThread(NULL, 0, audin_server_thread_func, (void*)audin, 0, NULL)))
490 {
491 WLog_Print(audin->log, WLOG_ERROR, "CreateThread failed!");
492 (void)CloseHandle(audin->stopEvent);
493 audin->stopEvent = NULL;
494 return FALSE;
495 }
496
497 return TRUE;
498 }
499
500 WLog_Print(audin->log, WLOG_ERROR, "thread already running!");
501 return FALSE;
502}
503
504static BOOL audin_server_is_open(audin_server_context* context)
505{
506 audin_server* audin = (audin_server*)context;
507
508 WINPR_ASSERT(audin);
509 return audin->thread != NULL;
510}
511
512static BOOL audin_server_close(audin_server_context* context)
513{
514 audin_server* audin = (audin_server*)context;
515 WINPR_ASSERT(audin);
516
517 if (audin->thread)
518 {
519 (void)SetEvent(audin->stopEvent);
520
521 if (WaitForSingleObject(audin->thread, INFINITE) == WAIT_FAILED)
522 {
523 WLog_Print(audin->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "",
524 GetLastError());
525 return FALSE;
526 }
527
528 (void)CloseHandle(audin->thread);
529 (void)CloseHandle(audin->stopEvent);
530 audin->thread = NULL;
531 audin->stopEvent = NULL;
532 }
533
534 if (audin->audin_channel)
535 {
536 (void)WTSVirtualChannelClose(audin->audin_channel);
537 audin->audin_channel = NULL;
538 }
539
540 audin->audin_negotiated_format = NULL;
541
542 return TRUE;
543}
544
545static wStream* audin_server_packet_new(wLog* log, size_t size, BYTE MessageId)
546{
547 WINPR_ASSERT(log);
548
549 /* Allocate what we need plus header bytes */
550 wStream* s = Stream_New(NULL, size + SNDIN_HEADER_SIZE);
551 if (!s)
552 {
553 WLog_Print(log, WLOG_ERROR, "Stream_New failed!");
554 return NULL;
555 }
556
557 Stream_Write_UINT8(s, MessageId);
558
559 return s;
560}
561
562static UINT audin_server_packet_send(audin_server_context* context, wStream* s)
563{
564 audin_server* audin = (audin_server*)context;
565 UINT error = CHANNEL_RC_OK;
566 ULONG written = 0;
567
568 WINPR_ASSERT(context);
569 WINPR_ASSERT(s);
570
571 const size_t pos = Stream_GetPosition(s);
572 WINPR_ASSERT(pos <= UINT32_MAX);
573 if (!WTSVirtualChannelWrite(audin->audin_channel, Stream_BufferAs(s, char), (UINT32)pos,
574 &written))
575 {
576 WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelWrite failed!");
577 error = ERROR_INTERNAL_ERROR;
578 goto out;
579 }
580
581 if (written < Stream_GetPosition(s))
582 {
583 WLog_Print(audin->log, WLOG_WARN, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "",
584 written, Stream_GetPosition(s));
585 }
586
587out:
588 Stream_Free(s, TRUE);
589 return error;
590}
591
592static UINT audin_server_send_version(audin_server_context* context, const SNDIN_VERSION* version)
593{
594 audin_server* audin = (audin_server*)context;
595
596 WINPR_ASSERT(context);
597 WINPR_ASSERT(version);
598
599 wStream* s = audin_server_packet_new(audin->log, 4, MSG_SNDIN_VERSION);
600 if (!s)
601 return ERROR_NOT_ENOUGH_MEMORY;
602
603 Stream_Write_UINT32(s, version->Version);
604
605 return audin_server_packet_send(context, s);
606}
607
608static UINT audin_server_send_formats(audin_server_context* context, const SNDIN_FORMATS* formats)
609{
610 audin_server* audin = (audin_server*)context;
611
612 WINPR_ASSERT(audin);
613 WINPR_ASSERT(formats);
614
615 wStream* s = audin_server_packet_new(audin->log, 4 + 4 + 18, MSG_SNDIN_FORMATS);
616 if (!s)
617 return ERROR_NOT_ENOUGH_MEMORY;
618
619 Stream_Write_UINT32(s, formats->NumFormats);
620 Stream_Write_UINT32(s, formats->cbSizeFormatsPacket);
621
622 for (UINT32 i = 0; i < formats->NumFormats; ++i)
623 {
624 AUDIO_FORMAT* format = &formats->SoundFormats[i];
625
626 if (!audio_format_write(s, format))
627 {
628 WLog_Print(audin->log, WLOG_ERROR, "Failed to write audio format");
629 Stream_Free(s, TRUE);
630 return CHANNEL_RC_NO_MEMORY;
631 }
632 }
633
634 return audin_server_packet_send(context, s);
635}
636
637static UINT audin_server_send_open(audin_server_context* context, const SNDIN_OPEN* open)
638{
639 audin_server* audin = (audin_server*)context;
640 WINPR_ASSERT(audin);
641 WINPR_ASSERT(open);
642
643 wStream* s = audin_server_packet_new(audin->log, 4 + 4 + 18 + 22, MSG_SNDIN_OPEN);
644 if (!s)
645 return ERROR_NOT_ENOUGH_MEMORY;
646
647 Stream_Write_UINT32(s, open->FramesPerPacket);
648 Stream_Write_UINT32(s, open->initialFormat);
649
650 Stream_Write_UINT16(s, open->captureFormat.wFormatTag);
651 Stream_Write_UINT16(s, open->captureFormat.nChannels);
652 Stream_Write_UINT32(s, open->captureFormat.nSamplesPerSec);
653 Stream_Write_UINT32(s, open->captureFormat.nAvgBytesPerSec);
654 Stream_Write_UINT16(s, open->captureFormat.nBlockAlign);
655 Stream_Write_UINT16(s, open->captureFormat.wBitsPerSample);
656
657 if (open->ExtraFormatData)
658 {
659 Stream_Write_UINT16(s, 22); /* cbSize */
660
661 Stream_Write_UINT16(s, open->ExtraFormatData->Samples.wReserved);
662 Stream_Write_UINT32(s, open->ExtraFormatData->dwChannelMask);
663
664 Stream_Write_UINT32(s, open->ExtraFormatData->SubFormat.Data1);
665 Stream_Write_UINT16(s, open->ExtraFormatData->SubFormat.Data2);
666 Stream_Write_UINT16(s, open->ExtraFormatData->SubFormat.Data3);
667 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[0]);
668 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[1]);
669 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[2]);
670 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[3]);
671 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[4]);
672 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[5]);
673 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[6]);
674 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[7]);
675 }
676 else
677 {
678 WINPR_ASSERT(open->captureFormat.wFormatTag != WAVE_FORMAT_EXTENSIBLE);
679
680 Stream_Write_UINT16(s, 0); /* cbSize */
681 }
682
683 return audin_server_packet_send(context, s);
684}
685
686static UINT audin_server_send_format_change(audin_server_context* context,
687 const SNDIN_FORMATCHANGE* format_change)
688{
689 audin_server* audin = (audin_server*)context;
690
691 WINPR_ASSERT(context);
692 WINPR_ASSERT(format_change);
693
694 wStream* s = audin_server_packet_new(audin->log, 4, MSG_SNDIN_FORMATCHANGE);
695 if (!s)
696 return ERROR_NOT_ENOUGH_MEMORY;
697
698 Stream_Write_UINT32(s, format_change->NewFormat);
699
700 return audin_server_packet_send(context, s);
701}
702
703static UINT audin_server_receive_version_default(audin_server_context* audin_ctx,
704 const SNDIN_VERSION* version)
705{
706 audin_server* audin = (audin_server*)audin_ctx;
707 SNDIN_FORMATS formats = { 0 };
708
709 WINPR_ASSERT(audin);
710 WINPR_ASSERT(version);
711
712 if (version->Version == 0)
713 {
714 WLog_Print(audin->log, WLOG_ERROR, "Received invalid AUDIO_INPUT version from client");
715 return ERROR_INVALID_DATA;
716 }
717
718 WLog_Print(audin->log, WLOG_DEBUG, "AUDIO_INPUT version of client: %u", version->Version);
719
720 formats.NumFormats = audin->audin_n_server_formats;
721 formats.SoundFormats = audin->audin_server_formats;
722
723 return audin->context.SendFormats(&audin->context, &formats);
724}
725
726static UINT send_open(audin_server* audin)
727{
728 SNDIN_OPEN open = { 0 };
729
730 WINPR_ASSERT(audin);
731
732 open.FramesPerPacket = 441;
733 open.initialFormat = audin->audin_client_format_idx;
734 open.captureFormat.wFormatTag = WAVE_FORMAT_PCM;
735 open.captureFormat.nChannels = 2;
736 open.captureFormat.nSamplesPerSec = 44100;
737 open.captureFormat.nAvgBytesPerSec = 44100 * 2 * 2;
738 open.captureFormat.nBlockAlign = 4;
739 open.captureFormat.wBitsPerSample = 16;
740
741 WINPR_ASSERT(audin->context.SendOpen);
742 return audin->context.SendOpen(&audin->context, &open);
743}
744
745static UINT audin_server_receive_formats_default(audin_server_context* context,
746 const SNDIN_FORMATS* formats)
747{
748 audin_server* audin = (audin_server*)context;
749 WINPR_ASSERT(audin);
750 WINPR_ASSERT(formats);
751
752 if (audin->audin_negotiated_format)
753 {
754 WLog_Print(audin->log, WLOG_ERROR,
755 "Received client formats, but negotiation was already done");
756 return ERROR_INVALID_DATA;
757 }
758
759 for (UINT32 i = 0; i < audin->audin_n_server_formats; ++i)
760 {
761 for (UINT32 j = 0; j < formats->NumFormats; ++j)
762 {
763 if (audio_format_compatible(&audin->audin_server_formats[i], &formats->SoundFormats[j]))
764 {
765 audin->audin_negotiated_format = &audin->audin_server_formats[i];
766 audin->audin_client_format_idx = i;
767 return send_open(audin);
768 }
769 }
770 }
771
772 WLog_Print(audin->log, WLOG_ERROR, "Could not agree on a audio format with the server");
773
774 return ERROR_INVALID_DATA;
775}
776
777static UINT audin_server_receive_format_change_default(audin_server_context* context,
778 const SNDIN_FORMATCHANGE* format_change)
779{
780 audin_server* audin = (audin_server*)context;
781
782 WINPR_ASSERT(audin);
783 WINPR_ASSERT(format_change);
784
785 if (format_change->NewFormat != audin->audin_client_format_idx)
786 {
787 WLog_Print(audin->log, WLOG_ERROR,
788 "NewFormat in FormatChange differs from requested format");
789 return ERROR_INVALID_DATA;
790 }
791
792 WLog_Print(audin->log, WLOG_DEBUG, "Received Format Change PDU: %u", format_change->NewFormat);
793
794 return CHANNEL_RC_OK;
795}
796
797static UINT
798audin_server_incoming_data_default(audin_server_context* context,
799 WINPR_ATTR_UNUSED const SNDIN_DATA_INCOMING* data_incoming)
800{
801 audin_server* audin = (audin_server*)context;
802 WINPR_ASSERT(audin);
803 WINPR_ASSERT(data_incoming);
804
805 /* TODO: Implement bandwidth measure of clients uplink */
806 WLog_Print(audin->log, WLOG_DEBUG, "Received Incoming Data PDU");
807 return CHANNEL_RC_OK;
808}
809
810static UINT audin_server_open_reply_default(audin_server_context* context,
811 const SNDIN_OPEN_REPLY* open_reply)
812{
813 audin_server* audin = (audin_server*)context;
814 WINPR_ASSERT(audin);
815 WINPR_ASSERT(open_reply);
816
817 /* TODO: Implement failure handling */
818 WLog_Print(audin->log, WLOG_DEBUG, "Open Reply PDU: Result: %i", open_reply->Result);
819 return CHANNEL_RC_OK;
820}
821
822audin_server_context* audin_server_context_new(HANDLE vcm)
823{
824 audin_server* audin = (audin_server*)calloc(1, sizeof(audin_server));
825
826 if (!audin)
827 {
828 WLog_ERR(AUDIN_TAG, "calloc failed!");
829 return NULL;
830 }
831 audin->log = WLog_Get(AUDIN_TAG);
832 audin->context.vcm = vcm;
833 audin->context.Open = audin_server_open;
834 audin->context.IsOpen = audin_server_is_open;
835 audin->context.Close = audin_server_close;
836
837 audin->context.SendVersion = audin_server_send_version;
838 audin->context.SendFormats = audin_server_send_formats;
839 audin->context.SendOpen = audin_server_send_open;
840 audin->context.SendFormatChange = audin_server_send_format_change;
841
842 /* Default values */
843 audin->context.serverVersion = SNDIN_VERSION_Version_2;
844 audin->context.ReceiveVersion = audin_server_receive_version_default;
845 audin->context.ReceiveFormats = audin_server_receive_formats_default;
846 audin->context.ReceiveFormatChange = audin_server_receive_format_change_default;
847 audin->context.IncomingData = audin_server_incoming_data_default;
848 audin->context.OpenReply = audin_server_open_reply_default;
849
850 return &audin->context;
851}
852
853void audin_server_context_free(audin_server_context* context)
854{
855 audin_server* audin = (audin_server*)context;
856
857 if (!audin)
858 return;
859
860 audin_server_close(context);
861 audio_formats_free(audin->audin_server_formats, audin->audin_n_server_formats);
862 audin->audin_server_formats = NULL;
863 free(audin);
864}
865
866BOOL audin_server_set_formats(audin_server_context* context, SSIZE_T count,
867 const AUDIO_FORMAT* formats)
868{
869 audin_server* audin = (audin_server*)context;
870 WINPR_ASSERT(audin);
871
872 audio_formats_free(audin->audin_server_formats, audin->audin_n_server_formats);
873 audin->audin_n_server_formats = 0;
874 audin->audin_server_formats = NULL;
875 audin->audin_negotiated_format = NULL;
876
877 if (count < 0)
878 {
879 const size_t audin_n_server_formats =
880 server_audin_get_formats(&audin->audin_server_formats);
881 WINPR_ASSERT(audin_n_server_formats <= UINT32_MAX);
882
883 audin->audin_n_server_formats = (UINT32)audin_n_server_formats;
884 }
885 else
886 {
887 const size_t scount = (size_t)count;
888 AUDIO_FORMAT* audin_server_formats = audio_formats_new(scount);
889 if (!audin_server_formats)
890 return count == 0;
891
892 for (SSIZE_T x = 0; x < count; x++)
893 {
894 if (!audio_format_copy(&formats[x], &audin_server_formats[x]))
895 {
896 audio_formats_free(audin_server_formats, scount);
897 return FALSE;
898 }
899 }
900
901 WINPR_ASSERT(count <= UINT32_MAX);
902 audin->audin_server_formats = audin_server_formats;
903 audin->audin_n_server_formats = (UINT32)count;
904 }
905 return audin->audin_n_server_formats > 0;
906}
907
908const AUDIO_FORMAT* audin_server_get_negotiated_format(const audin_server_context* context)
909{
910 const audin_server* audin = (const audin_server*)context;
911 WINPR_ASSERT(audin);
912
913 return audin->audin_negotiated_format;
914}