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