23#include <freerdp/config.h>
26#include <winpr/assert.h>
27#include <winpr/synch.h>
28#include <winpr/thread.h>
29#include <winpr/stream.h>
31#include <freerdp/freerdp.h>
32#include <freerdp/server/server-common.h>
33#include <freerdp/server/audin.h>
34#include <freerdp/channels/log.h>
36#define AUDIN_TAG CHANNELS_TAG("audin.server")
38#define SNDIN_HEADER_SIZE 1
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,
53 audin_server_context context;
63 UINT32 audin_n_server_formats;
65 UINT32 audin_client_format_idx;
69static UINT audin_server_recv_version(audin_server_context* context,
wStream* s,
72 audin_server* audin = (audin_server*)context;
74 UINT error = CHANNEL_RC_OK;
76 WINPR_ASSERT(context);
81 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4))
85 const UINT32 version = Stream_Get_UINT32(s);
88 case SNDIN_VERSION_Version_1:
89 pdu.Version = SNDIN_VERSION_Version_1;
91 case SNDIN_VERSION_Version_2:
92 pdu.Version = SNDIN_VERSION_Version_2;
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);
104 IFCALLRET(context->ReceiveVersion, error, context, &pdu);
106 WLog_Print(audin->log, WLOG_ERROR,
"context->ReceiveVersion failed with error %" PRIu32
"",
112static UINT audin_server_recv_formats(audin_server_context* context,
wStream* s,
115 audin_server* audin = (audin_server*)context;
117 UINT error = CHANNEL_RC_OK;
119 WINPR_ASSERT(context);
120 WINPR_ASSERT(header);
122 pdu.Header = *header;
125 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4 + 4 + 18))
126 return ERROR_NO_DATA;
128 Stream_Read_UINT32(s, pdu.NumFormats);
129 Stream_Read_UINT32(s, pdu.cbSizeFormatsPacket);
131 if (pdu.NumFormats == 0)
133 WLog_Print(audin->log, WLOG_ERROR,
"Sound Formats PDU contains no formats");
134 return ERROR_INVALID_DATA;
137 pdu.SoundFormats = audio_formats_new(pdu.NumFormats);
138 if (!pdu.SoundFormats)
140 WLog_Print(audin->log, WLOG_ERROR,
"Failed to allocate %u SoundFormats", pdu.NumFormats);
141 return ERROR_NOT_ENOUGH_MEMORY;
144 for (UINT32 i = 0; i < pdu.NumFormats; ++i)
148 if (!audio_format_read(s, format))
150 WLog_Print(audin->log, WLOG_ERROR,
"Failed to read audio format");
151 error = ERROR_INVALID_DATA;
155 audio_format_print(audin->log, WLOG_DEBUG, format);
158 if (pdu.cbSizeFormatsPacket != Stream_GetPosition(s))
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)
166 WLog_Print(audin->log, WLOG_ERROR,
"Stream too long, %" PRIuz
" exceeds UINT32_MAX",
168 error = ERROR_INVALID_PARAMETER;
171 pdu.cbSizeFormatsPacket = (UINT32)pos;
174 pdu.ExtraDataSize = Stream_GetRemainingLength(s);
176 IFCALLRET(context->ReceiveFormats, error, context, &pdu);
178 WLog_Print(audin->log, WLOG_ERROR,
"context->ReceiveFormats failed with error %" PRIu32
"",
182 audio_formats_free(pdu.SoundFormats, pdu.NumFormats);
187static UINT audin_server_recv_open_reply(audin_server_context* context,
wStream* s,
190 audin_server* audin = (audin_server*)context;
192 UINT error = CHANNEL_RC_OK;
194 WINPR_ASSERT(context);
195 WINPR_ASSERT(header);
197 pdu.Header = *header;
199 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4))
200 return ERROR_NO_DATA;
202 Stream_Read_UINT32(s, pdu.Result);
204 IFCALLRET(context->OpenReply, error, context, &pdu);
206 WLog_Print(audin->log, WLOG_ERROR,
"context->OpenReply failed with error %" PRIu32
"",
212static UINT audin_server_recv_data_incoming(audin_server_context* context,
215 audin_server* audin = (audin_server*)context;
217 UINT error = CHANNEL_RC_OK;
219 WINPR_ASSERT(context);
220 WINPR_ASSERT(header);
222 pdu.Header = *header;
224 IFCALLRET(context->IncomingData, error, context, &pdu);
226 WLog_Print(audin->log, WLOG_ERROR,
"context->IncomingData failed with error %" PRIu32
"",
232static UINT audin_server_recv_data(audin_server_context* context,
wStream* s,
235 audin_server* audin = (audin_server*)context;
237 wStream dataBuffer = WINPR_C_ARRAY_INIT;
238 UINT error = CHANNEL_RC_OK;
240 WINPR_ASSERT(context);
241 WINPR_ASSERT(header);
243 pdu.Header = *header;
245 pdu.Data = Stream_StaticInit(&dataBuffer, Stream_Pointer(s), Stream_GetRemainingLength(s));
247 IFCALLRET(context->Data, error, context, &pdu);
249 WLog_Print(audin->log, WLOG_ERROR,
"context->Data failed with error %" PRIu32
"", error);
254static UINT audin_server_recv_format_change(audin_server_context* context,
wStream* s,
257 audin_server* audin = (audin_server*)context;
259 UINT error = CHANNEL_RC_OK;
261 WINPR_ASSERT(context);
262 WINPR_ASSERT(header);
264 pdu.Header = *header;
266 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4))
267 return ERROR_NO_DATA;
269 Stream_Read_UINT32(s, pdu.NewFormat);
271 IFCALLRET(context->ReceiveFormatChange, error, context, &pdu);
273 WLog_Print(audin->log, WLOG_ERROR,
274 "context->ReceiveFormatChange failed with error %" PRIu32
"", error);
279static DWORD WINAPI audin_server_thread_func(LPVOID arg)
282 void* buffer =
nullptr;
284 HANDLE events[8] = WINPR_C_ARRAY_INIT;
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;
294 if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualEventHandle, &buffer,
295 &BytesReturned) == TRUE)
297 if (BytesReturned ==
sizeof(HANDLE))
298 ChannelEvent = *(HANDLE*)buffer;
300 WTSFreeMemory(buffer);
304 WLog_Print(audin->log, WLOG_ERROR,
"WTSVirtualChannelQuery failed");
305 error = ERROR_INTERNAL_ERROR;
310 events[nCount++] = audin->stopEvent;
311 events[nCount++] = ChannelEvent;
317 status = WaitForMultipleObjects(nCount, events, FALSE, 100);
319 if (status == WAIT_FAILED)
321 error = GetLastError();
322 WLog_Print(audin->log, WLOG_ERROR,
323 "WaitForMultipleObjects failed with error %" PRIu32
"", error);
326 if (status == WAIT_OBJECT_0)
329 if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer,
330 &BytesReturned) == FALSE)
332 WLog_Print(audin->log, WLOG_ERROR,
"WTSVirtualChannelQuery failed");
333 error = ERROR_INTERNAL_ERROR;
337 ready = *((BOOL*)buffer);
338 WTSFreeMemory(buffer);
344 s = Stream_New(
nullptr, 4096);
348 WLog_Print(audin->log, WLOG_ERROR,
"Stream_New failed!");
349 error = CHANNEL_RC_NO_MEMORY;
357 version.Version = audin->context.serverVersion;
359 if ((error = audin->context.SendVersion(&audin->context, &version)))
361 WLog_Print(audin->log, WLOG_ERROR,
"SendVersion failed with error %" PRIu32
"!", error);
370 if ((status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE)) == WAIT_OBJECT_0)
373 if (status == WAIT_FAILED)
375 error = GetLastError();
376 WLog_Print(audin->log, WLOG_ERROR,
377 "WaitForMultipleObjects failed with error %" PRIu32
"", error);
380 if (status == WAIT_OBJECT_0)
383 Stream_ResetPosition(s);
385 if (!WTSVirtualChannelRead(audin->audin_channel, 0,
nullptr, 0, &BytesReturned))
387 WLog_Print(audin->log, WLOG_ERROR,
"WTSVirtualChannelRead failed!");
388 error = ERROR_INTERNAL_ERROR;
392 if (BytesReturned < 1)
395 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
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)
402 WLog_Print(audin->log, WLOG_ERROR,
"WTSVirtualChannelRead failed!");
403 error = ERROR_INTERNAL_ERROR;
407 if (!Stream_SafeSeek(s, BytesReturned))
409 error = ERROR_INTERNAL_ERROR;
413 if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, SNDIN_HEADER_SIZE))
415 error = ERROR_INTERNAL_ERROR;
419 Stream_Read_UINT8(s, header.MessageId);
421 switch (header.MessageId)
423 case MSG_SNDIN_VERSION:
424 error = audin_server_recv_version(&audin->context, s, &header);
426 case MSG_SNDIN_FORMATS:
427 error = audin_server_recv_formats(&audin->context, s, &header);
429 case MSG_SNDIN_OPEN_REPLY:
430 error = audin_server_recv_open_reply(&audin->context, s, &header);
432 case MSG_SNDIN_DATA_INCOMING:
433 error = audin_server_recv_data_incoming(&audin->context, s, &header);
436 error = audin_server_recv_data(&audin->context, s, &header);
438 case MSG_SNDIN_FORMATCHANGE:
439 error = audin_server_recv_format_change(&audin->context, s, &header);
442 WLog_Print(audin->log, WLOG_ERROR,
443 "audin_server_thread_func: unknown or invalid MessageId %" PRIu8
"",
445 error = ERROR_INVALID_DATA;
453 Stream_Free(s, TRUE);
455 (void)WTSVirtualChannelClose(audin->audin_channel);
456 audin->audin_channel =
nullptr;
458 if (error && audin->context.rdpcontext)
459 setChannelError(audin->context.rdpcontext, error,
460 "audin_server_thread_func reported an error");
466static BOOL audin_server_open(audin_server_context* context)
468 audin_server* audin = (audin_server*)context;
473 PULONG pSessionId =
nullptr;
474 DWORD BytesReturned = 0;
475 audin->SessionId = WTS_CURRENT_SESSION;
476 UINT32 channelId = 0;
479 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
480 (LPSTR*)&pSessionId, &BytesReturned))
482 audin->SessionId = (DWORD)*pSessionId;
483 WTSFreeMemory(pSessionId);
486 audin->audin_channel = WTSVirtualChannelOpenEx(audin->SessionId, AUDIN_DVC_CHANNEL_NAME,
487 WTS_CHANNEL_OPTION_DYNAMIC);
489 if (!audin->audin_channel)
491 WLog_Print(audin->log, WLOG_ERROR,
"WTSVirtualChannelOpenEx failed!");
495 channelId = WTSChannelGetIdByHandle(audin->audin_channel);
497 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
500 WLog_Print(audin->log, WLOG_ERROR,
"context->ChannelIdAssigned failed!");
504 if (!(audin->stopEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
506 WLog_Print(audin->log, WLOG_ERROR,
"CreateEvent failed!");
510 if (!(audin->thread =
511 CreateThread(
nullptr, 0, audin_server_thread_func, (
void*)audin, 0,
nullptr)))
513 WLog_Print(audin->log, WLOG_ERROR,
"CreateThread failed!");
514 (void)CloseHandle(audin->stopEvent);
515 audin->stopEvent =
nullptr;
522 WLog_Print(audin->log, WLOG_ERROR,
"thread already running!");
526static BOOL audin_server_is_open(audin_server_context* context)
528 audin_server* audin = (audin_server*)context;
531 return audin->thread !=
nullptr;
534static BOOL audin_server_close(audin_server_context* context)
536 audin_server* audin = (audin_server*)context;
541 (void)SetEvent(audin->stopEvent);
543 if (WaitForSingleObject(audin->thread, INFINITE) == WAIT_FAILED)
545 WLog_Print(audin->log, WLOG_ERROR,
"WaitForSingleObject failed with error %" PRIu32
"",
550 (void)CloseHandle(audin->thread);
551 (void)CloseHandle(audin->stopEvent);
552 audin->thread =
nullptr;
553 audin->stopEvent =
nullptr;
556 if (audin->audin_channel)
558 (void)WTSVirtualChannelClose(audin->audin_channel);
559 audin->audin_channel =
nullptr;
562 audin->audin_negotiated_format =
nullptr;
567static wStream* audin_server_packet_new(wLog* log,
size_t size, BYTE MessageId)
572 wStream* s = Stream_New(
nullptr, size + SNDIN_HEADER_SIZE);
575 WLog_Print(log, WLOG_ERROR,
"Stream_New failed!");
579 Stream_Write_UINT8(s, MessageId);
584static UINT audin_server_packet_send(audin_server_context* context,
wStream* s)
586 audin_server* audin = (audin_server*)context;
587 UINT error = CHANNEL_RC_OK;
590 WINPR_ASSERT(context);
593 const size_t pos = Stream_GetPosition(s);
594 WINPR_ASSERT(pos <= UINT32_MAX);
595 if (!WTSVirtualChannelWrite(audin->audin_channel, Stream_BufferAs(s,
char), (UINT32)pos,
598 WLog_Print(audin->log, WLOG_ERROR,
"WTSVirtualChannelWrite failed!");
599 error = ERROR_INTERNAL_ERROR;
603 if (written < Stream_GetPosition(s))
605 WLog_Print(audin->log, WLOG_WARN,
"Unexpected bytes written: %" PRIu32
"/%" PRIuz
"",
606 written, Stream_GetPosition(s));
610 Stream_Free(s, TRUE);
614static UINT audin_server_send_version(audin_server_context* context,
const SNDIN_VERSION* version)
616 audin_server* audin = (audin_server*)context;
618 WINPR_ASSERT(context);
619 WINPR_ASSERT(version);
621 wStream* s = audin_server_packet_new(audin->log, 4, MSG_SNDIN_VERSION);
623 return ERROR_NOT_ENOUGH_MEMORY;
625 Stream_Write_UINT32(s, version->Version);
627 return audin_server_packet_send(context, s);
630static UINT audin_server_send_formats(audin_server_context* context,
const SNDIN_FORMATS* formats)
632 audin_server* audin = (audin_server*)context;
635 WINPR_ASSERT(formats);
637 wStream* s = audin_server_packet_new(audin->log, 4 + 4 + 18, MSG_SNDIN_FORMATS);
639 return ERROR_NOT_ENOUGH_MEMORY;
641 Stream_Write_UINT32(s, formats->NumFormats);
642 Stream_Write_UINT32(s, formats->cbSizeFormatsPacket);
644 for (UINT32 i = 0; i < formats->NumFormats; ++i)
648 if (!audio_format_write(s, format))
650 WLog_Print(audin->log, WLOG_ERROR,
"Failed to write audio format");
651 Stream_Free(s, TRUE);
652 return CHANNEL_RC_NO_MEMORY;
656 return audin_server_packet_send(context, s);
659static UINT audin_server_send_open(audin_server_context* context,
const SNDIN_OPEN* open)
661 audin_server* audin = (audin_server*)context;
665 wStream* s = audin_server_packet_new(audin->log, 4 + 4 + 18 + 22, MSG_SNDIN_OPEN);
667 return ERROR_NOT_ENOUGH_MEMORY;
669 Stream_Write_UINT32(s, open->FramesPerPacket);
670 Stream_Write_UINT32(s, open->initialFormat);
672 Stream_Write_UINT16(s, open->captureFormat.wFormatTag);
673 Stream_Write_UINT16(s, open->captureFormat.nChannels);
674 Stream_Write_UINT32(s, open->captureFormat.nSamplesPerSec);
675 Stream_Write_UINT32(s, open->captureFormat.nAvgBytesPerSec);
676 Stream_Write_UINT16(s, open->captureFormat.nBlockAlign);
677 Stream_Write_UINT16(s, open->captureFormat.wBitsPerSample);
679 if (open->ExtraFormatData)
681 Stream_Write_UINT16(s, 22);
683 Stream_Write_UINT16(s, open->ExtraFormatData->Samples.wReserved);
684 Stream_Write_UINT32(s, open->ExtraFormatData->dwChannelMask);
686 Stream_Write_UINT32(s, open->ExtraFormatData->SubFormat.Data1);
687 Stream_Write_UINT16(s, open->ExtraFormatData->SubFormat.Data2);
688 Stream_Write_UINT16(s, open->ExtraFormatData->SubFormat.Data3);
689 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[0]);
690 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[1]);
691 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[2]);
692 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[3]);
693 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[4]);
694 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[5]);
695 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[6]);
696 Stream_Write_UINT8(s, open->ExtraFormatData->SubFormat.Data4[7]);
700 WINPR_ASSERT(open->captureFormat.wFormatTag != WAVE_FORMAT_EXTENSIBLE);
702 Stream_Write_UINT16(s, 0);
705 return audin_server_packet_send(context, s);
708static UINT audin_server_send_format_change(audin_server_context* context,
711 audin_server* audin = (audin_server*)context;
713 WINPR_ASSERT(context);
714 WINPR_ASSERT(format_change);
716 wStream* s = audin_server_packet_new(audin->log, 4, MSG_SNDIN_FORMATCHANGE);
718 return ERROR_NOT_ENOUGH_MEMORY;
720 Stream_Write_UINT32(s, format_change->NewFormat);
722 return audin_server_packet_send(context, s);
725static UINT audin_server_receive_version_default(audin_server_context* audin_ctx,
728 audin_server* audin = (audin_server*)audin_ctx;
732 WINPR_ASSERT(version);
734 if (version->Version == 0)
736 WLog_Print(audin->log, WLOG_ERROR,
"Received invalid AUDIO_INPUT version from client");
737 return ERROR_INVALID_DATA;
740 WLog_Print(audin->log, WLOG_DEBUG,
"AUDIO_INPUT version of client: %u", version->Version);
742 formats.NumFormats = audin->audin_n_server_formats;
743 formats.SoundFormats = audin->audin_server_formats;
745 return audin->context.SendFormats(&audin->context, &formats);
748static UINT send_open(audin_server* audin)
754 open.FramesPerPacket = 441;
755 open.initialFormat = audin->audin_client_format_idx;
756 open.captureFormat.wFormatTag = WAVE_FORMAT_PCM;
757 open.captureFormat.nChannels = 2;
758 open.captureFormat.nSamplesPerSec = 44100;
759 open.captureFormat.nAvgBytesPerSec = 44100 * 2 * 2;
760 open.captureFormat.nBlockAlign = 4;
761 open.captureFormat.wBitsPerSample = 16;
763 WINPR_ASSERT(audin->context.SendOpen);
764 return audin->context.SendOpen(&audin->context, &open);
767static UINT audin_server_receive_formats_default(audin_server_context* context,
770 audin_server* audin = (audin_server*)context;
772 WINPR_ASSERT(formats);
774 if (audin->audin_negotiated_format)
776 WLog_Print(audin->log, WLOG_ERROR,
777 "Received client formats, but negotiation was already done");
778 return ERROR_INVALID_DATA;
781 for (UINT32 i = 0; i < audin->audin_n_server_formats; ++i)
783 for (UINT32 j = 0; j < formats->NumFormats; ++j)
785 if (audio_format_compatible(&audin->audin_server_formats[i], &formats->SoundFormats[j]))
787 audin->audin_negotiated_format = &audin->audin_server_formats[i];
788 audin->audin_client_format_idx = i;
789 return send_open(audin);
794 WLog_Print(audin->log, WLOG_ERROR,
"Could not agree on a audio format with the server");
796 return ERROR_INVALID_DATA;
799static UINT audin_server_receive_format_change_default(audin_server_context* context,
802 audin_server* audin = (audin_server*)context;
805 WINPR_ASSERT(format_change);
807 if (format_change->NewFormat != audin->audin_client_format_idx)
809 WLog_Print(audin->log, WLOG_ERROR,
810 "NewFormat in FormatChange differs from requested format");
811 return ERROR_INVALID_DATA;
814 WLog_Print(audin->log, WLOG_DEBUG,
"Received Format Change PDU: %u", format_change->NewFormat);
816 return CHANNEL_RC_OK;
820audin_server_incoming_data_default(audin_server_context* context,
823 audin_server* audin = (audin_server*)context;
825 WINPR_ASSERT(data_incoming);
828 WLog_Print(audin->log, WLOG_DEBUG,
"Received Incoming Data PDU");
829 return CHANNEL_RC_OK;
832static UINT audin_server_open_reply_default(audin_server_context* context,
835 audin_server* audin = (audin_server*)context;
837 WINPR_ASSERT(open_reply);
840 WLog_Print(audin->log, WLOG_DEBUG,
"Open Reply PDU: Result: %" PRIu32, open_reply->Result);
841 return CHANNEL_RC_OK;
844audin_server_context* audin_server_context_new(HANDLE vcm)
846 audin_server* audin = (audin_server*)calloc(1,
sizeof(audin_server));
850 WLog_ERR(AUDIN_TAG,
"calloc failed!");
853 audin->log = WLog_Get(AUDIN_TAG);
854 audin->context.vcm = vcm;
855 audin->context.Open = audin_server_open;
856 audin->context.IsOpen = audin_server_is_open;
857 audin->context.Close = audin_server_close;
859 audin->context.SendVersion = audin_server_send_version;
860 audin->context.SendFormats = audin_server_send_formats;
861 audin->context.SendOpen = audin_server_send_open;
862 audin->context.SendFormatChange = audin_server_send_format_change;
865 audin->context.serverVersion = SNDIN_VERSION_Version_2;
866 audin->context.ReceiveVersion = audin_server_receive_version_default;
867 audin->context.ReceiveFormats = audin_server_receive_formats_default;
868 audin->context.ReceiveFormatChange = audin_server_receive_format_change_default;
869 audin->context.IncomingData = audin_server_incoming_data_default;
870 audin->context.OpenReply = audin_server_open_reply_default;
872 return &audin->context;
875void audin_server_context_free(audin_server_context* context)
877 audin_server* audin = (audin_server*)context;
882 audin_server_close(context);
883 audio_formats_free(audin->audin_server_formats, audin->audin_n_server_formats);
884 audin->audin_server_formats =
nullptr;
888BOOL audin_server_set_formats(audin_server_context* context, SSIZE_T count,
891 audin_server* audin = (audin_server*)context;
894 audio_formats_free(audin->audin_server_formats, audin->audin_n_server_formats);
895 audin->audin_n_server_formats = 0;
896 audin->audin_server_formats =
nullptr;
897 audin->audin_negotiated_format =
nullptr;
901 const size_t audin_n_server_formats =
902 server_audin_get_formats(&audin->audin_server_formats);
903 WINPR_ASSERT(audin_n_server_formats <= UINT32_MAX);
905 audin->audin_n_server_formats = (UINT32)audin_n_server_formats;
909 const size_t scount = (size_t)count;
910 AUDIO_FORMAT* audin_server_formats = audio_formats_new(scount);
911 if (!audin_server_formats)
914 for (SSIZE_T x = 0; x < count; x++)
916 if (!audio_format_copy(&formats[x], &audin_server_formats[x]))
918 audio_formats_free(audin_server_formats, scount);
923 WINPR_ASSERT(count <= UINT32_MAX);
924 audin->audin_server_formats = audin_server_formats;
925 audin->audin_n_server_formats = (UINT32)count;
927 return audin->audin_n_server_formats > 0;
930const AUDIO_FORMAT* audin_server_get_negotiated_format(
const audin_server_context* context)
932 const audin_server* audin = (
const audin_server*)context;
935 return audin->audin_negotiated_format;