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