FreeRDP
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 
40 typedef 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 
51 typedef 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 
69 static 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 
94 static 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 
163 fail:
164  audio_formats_free(pdu.SoundFormats, pdu.NumFormats);
165 
166  return error;
167 }
168 
169 static 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 
194 static UINT audin_server_recv_data_incoming(audin_server_context* context, wStream* s,
195  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 
214 static 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 
236 static 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 
261 static 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  CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
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 
430 out_capacity:
431  Stream_Free(s, TRUE);
432 out:
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 
444 static 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 
504 static 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 
512 static 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 
545 static 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 
562 static 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 
587 out:
588  Stream_Free(s, TRUE);
589  return error;
590 }
591 
592 static 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 
608 static 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 
637 static 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 
686 static 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 
703 static 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 
726 static 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 
745 static 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 
777 static 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 
797 static UINT audin_server_incoming_data_default(audin_server_context* context,
798  const SNDIN_DATA_INCOMING* data_incoming)
799 {
800  audin_server* audin = (audin_server*)context;
801  WINPR_ASSERT(audin);
802  WINPR_ASSERT(data_incoming);
803 
804  /* TODO: Implement bandwidth measure of clients uplink */
805  WLog_Print(audin->log, WLOG_DEBUG, "Received Incoming Data PDU");
806  return CHANNEL_RC_OK;
807 }
808 
809 static UINT audin_server_open_reply_default(audin_server_context* context,
810  const SNDIN_OPEN_REPLY* open_reply)
811 {
812  audin_server* audin = (audin_server*)context;
813  WINPR_ASSERT(audin);
814  WINPR_ASSERT(open_reply);
815 
816  /* TODO: Implement failure handling */
817  WLog_Print(audin->log, WLOG_DEBUG, "Open Reply PDU: Result: %i", open_reply->Result);
818  return CHANNEL_RC_OK;
819 }
820 
821 audin_server_context* audin_server_context_new(HANDLE vcm)
822 {
823  audin_server* audin = (audin_server*)calloc(1, sizeof(audin_server));
824 
825  if (!audin)
826  {
827  WLog_ERR(AUDIN_TAG, "calloc failed!");
828  return NULL;
829  }
830  audin->log = WLog_Get(AUDIN_TAG);
831  audin->context.vcm = vcm;
832  audin->context.Open = audin_server_open;
833  audin->context.IsOpen = audin_server_is_open;
834  audin->context.Close = audin_server_close;
835 
836  audin->context.SendVersion = audin_server_send_version;
837  audin->context.SendFormats = audin_server_send_formats;
838  audin->context.SendOpen = audin_server_send_open;
839  audin->context.SendFormatChange = audin_server_send_format_change;
840 
841  /* Default values */
842  audin->context.serverVersion = SNDIN_VERSION_Version_2;
843  audin->context.ReceiveVersion = audin_server_receive_version_default;
844  audin->context.ReceiveFormats = audin_server_receive_formats_default;
845  audin->context.ReceiveFormatChange = audin_server_receive_format_change_default;
846  audin->context.IncomingData = audin_server_incoming_data_default;
847  audin->context.OpenReply = audin_server_open_reply_default;
848 
849  return &audin->context;
850 }
851 
852 void audin_server_context_free(audin_server_context* context)
853 {
854  audin_server* audin = (audin_server*)context;
855 
856  if (!audin)
857  return;
858 
859  audin_server_close(context);
860  audio_formats_free(audin->audin_server_formats, audin->audin_n_server_formats);
861  audin->audin_server_formats = NULL;
862  free(audin);
863 }
864 
865 BOOL audin_server_set_formats(audin_server_context* context, SSIZE_T count,
866  const AUDIO_FORMAT* formats)
867 {
868  audin_server* audin = (audin_server*)context;
869  WINPR_ASSERT(audin);
870 
871  audio_formats_free(audin->audin_server_formats, audin->audin_n_server_formats);
872  audin->audin_n_server_formats = 0;
873  audin->audin_server_formats = NULL;
874  audin->audin_negotiated_format = NULL;
875 
876  if (count < 0)
877  {
878  const size_t audin_n_server_formats =
879  server_audin_get_formats(&audin->audin_server_formats);
880  WINPR_ASSERT(audin_n_server_formats <= UINT32_MAX);
881 
882  audin->audin_n_server_formats = (UINT32)audin_n_server_formats;
883  }
884  else
885  {
886  AUDIO_FORMAT* audin_server_formats = audio_formats_new(count);
887  if (!audin_server_formats)
888  return count == 0;
889 
890  for (SSIZE_T x = 0; x < count; x++)
891  {
892  if (!audio_format_copy(&formats[x], &audin_server_formats[x]))
893  {
894  audio_formats_free(audin_server_formats, count);
895  return FALSE;
896  }
897  }
898 
899  WINPR_ASSERT(count <= UINT32_MAX);
900  audin->audin_server_formats = audin_server_formats;
901  audin->audin_n_server_formats = (UINT32)count;
902  }
903  return audin->audin_n_server_formats > 0;
904 }
905 
906 const AUDIO_FORMAT* audin_server_get_negotiated_format(const audin_server_context* context)
907 {
908  const audin_server* audin = (const audin_server*)context;
909  WINPR_ASSERT(audin);
910 
911  return audin->audin_negotiated_format;
912 }