FreeRDP
client/rdpsnd_main.c
1 
25 #include <freerdp/config.h>
26 
27 #ifndef _WIN32
28 #include <sys/time.h>
29 #include <signal.h>
30 #endif
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 
37 #include <winpr/crt.h>
38 #include <winpr/assert.h>
39 #include <winpr/wlog.h>
40 #include <winpr/stream.h>
41 #include <winpr/cmdline.h>
42 #include <winpr/sysinfo.h>
43 #include <winpr/collections.h>
44 
45 #include <freerdp/types.h>
46 #include <freerdp/addin.h>
47 #include <freerdp/freerdp.h>
48 #include <freerdp/codec/dsp.h>
49 #include <freerdp/client/channels.h>
50 
51 #include "rdpsnd_common.h"
52 #include "rdpsnd_main.h"
53 
54 struct rdpsnd_plugin
55 {
56  IWTSPlugin iface;
57  IWTSListener* listener;
58  GENERIC_LISTENER_CALLBACK* listener_callback;
59 
60  CHANNEL_DEF channelDef;
61  CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints;
62 
63  wStreamPool* pool;
64  wStream* data_in;
65 
66  void* InitHandle;
67  DWORD OpenHandle;
68 
69  wLog* log;
70 
71  BYTE cBlockNo;
72  UINT16 wQualityMode;
73  UINT16 wCurrentFormatNo;
74 
75  AUDIO_FORMAT* ServerFormats;
76  UINT16 NumberOfServerFormats;
77 
78  AUDIO_FORMAT* ClientFormats;
79  UINT16 NumberOfClientFormats;
80 
81  BOOL attached;
82  BOOL connected;
83  BOOL dynamic;
84 
85  BOOL expectingWave;
86  BYTE waveData[4];
87  UINT16 waveDataSize;
88  UINT16 wTimeStamp;
89  UINT64 wArrivalTime;
90 
91  UINT32 latency;
92  BOOL isOpen;
93  AUDIO_FORMAT* fixed_format;
94 
95  UINT32 startPlayTime;
96  size_t totalPlaySize;
97 
98  char* subsystem;
99  char* device_name;
100 
101  /* Device plugin */
102  rdpsndDevicePlugin* device;
103  rdpContext* rdpcontext;
104 
105  FREERDP_DSP_CONTEXT* dsp_context;
106 
107  HANDLE thread;
108  wMessageQueue* queue;
109  BOOL initialized;
110 
111  UINT16 wVersion;
112  UINT32 volume;
113  BOOL applyVolume;
114 
115  size_t references;
116  BOOL OnOpenCalled;
117  BOOL async;
118 };
119 
120 static const char* rdpsnd_is_dyn_str(BOOL dynamic)
121 {
122  if (dynamic)
123  return "[dynamic]";
124  return "[static]";
125 }
126 
127 static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd);
128 
134 static UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s);
135 
141 static UINT rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd)
142 {
143  wStream* pdu = NULL;
144  WINPR_ASSERT(rdpsnd);
145  pdu = Stream_New(NULL, 8);
146 
147  if (!pdu)
148  {
149  WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic));
150  return CHANNEL_RC_NO_MEMORY;
151  }
152 
153  Stream_Write_UINT8(pdu, SNDC_QUALITYMODE); /* msgType */
154  Stream_Write_UINT8(pdu, 0); /* bPad */
155  Stream_Write_UINT16(pdu, 4); /* BodySize */
156  Stream_Write_UINT16(pdu, rdpsnd->wQualityMode); /* wQualityMode */
157  Stream_Write_UINT16(pdu, 0); /* Reserved */
158  WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s QualityMode: %" PRIu16 "",
159  rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->wQualityMode);
160  return rdpsnd_virtual_channel_write(rdpsnd, pdu);
161 }
162 
163 static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd)
164 {
165  WINPR_ASSERT(rdpsnd);
166  audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
167  rdpsnd->NumberOfClientFormats = 0;
168  rdpsnd->ClientFormats = NULL;
169 
170  if (!rdpsnd->NumberOfServerFormats)
171  return;
172 
173  rdpsnd->ClientFormats = audio_formats_new(rdpsnd->NumberOfServerFormats);
174 
175  if (!rdpsnd->ClientFormats || !rdpsnd->device)
176  return;
177 
178  for (UINT16 index = 0; index < rdpsnd->NumberOfServerFormats; index++)
179  {
180  const AUDIO_FORMAT* serverFormat = &rdpsnd->ServerFormats[index];
181 
182  if (!audio_format_compatible(rdpsnd->fixed_format, serverFormat))
183  continue;
184 
185  WINPR_ASSERT(rdpsnd->device->FormatSupported);
186  if (freerdp_dsp_supports_format(serverFormat, FALSE) ||
187  rdpsnd->device->FormatSupported(rdpsnd->device, serverFormat))
188  {
189  AUDIO_FORMAT* clientFormat = &rdpsnd->ClientFormats[rdpsnd->NumberOfClientFormats++];
190  audio_format_copy(serverFormat, clientFormat);
191  }
192  }
193 }
194 
200 static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd)
201 {
202  wStream* pdu = NULL;
203  UINT16 length = 0;
204  UINT32 dwVolume = 0;
205  UINT16 wNumberOfFormats = 0;
206  WINPR_ASSERT(rdpsnd);
207 
208  if (!rdpsnd->device || (!rdpsnd->dynamic && (rdpsnd->OpenHandle == 0)))
209  return CHANNEL_RC_INITIALIZATION_ERROR;
210 
211  dwVolume = IFCALLRESULT(0, rdpsnd->device->GetVolume, rdpsnd->device);
212  wNumberOfFormats = rdpsnd->NumberOfClientFormats;
213  length = 4 + 20;
214 
215  for (UINT16 index = 0; index < wNumberOfFormats; index++)
216  length += (18 + rdpsnd->ClientFormats[index].cbSize);
217 
218  pdu = Stream_New(NULL, length);
219 
220  if (!pdu)
221  {
222  WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic));
223  return CHANNEL_RC_NO_MEMORY;
224  }
225 
226  Stream_Write_UINT8(pdu, SNDC_FORMATS); /* msgType */
227  Stream_Write_UINT8(pdu, 0); /* bPad */
228  Stream_Write_UINT16(pdu, length - 4); /* BodySize */
229  Stream_Write_UINT32(pdu, TSSNDCAPS_ALIVE | TSSNDCAPS_VOLUME); /* dwFlags */
230  Stream_Write_UINT32(pdu, dwVolume); /* dwVolume */
231  Stream_Write_UINT32(pdu, 0); /* dwPitch */
232  Stream_Write_UINT16(pdu, 0); /* wDGramPort */
233  Stream_Write_UINT16(pdu, wNumberOfFormats); /* wNumberOfFormats */
234  Stream_Write_UINT8(pdu, 0); /* cLastBlockConfirmed */
235  Stream_Write_UINT16(pdu, CHANNEL_VERSION_WIN_MAX); /* wVersion */
236  Stream_Write_UINT8(pdu, 0); /* bPad */
237 
238  for (UINT16 index = 0; index < wNumberOfFormats; index++)
239  {
240  const AUDIO_FORMAT* clientFormat = &rdpsnd->ClientFormats[index];
241 
242  if (!audio_format_write(pdu, clientFormat))
243  {
244  Stream_Free(pdu, TRUE);
245  return ERROR_INTERNAL_ERROR;
246  }
247  }
248 
249  WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Client Audio Formats",
250  rdpsnd_is_dyn_str(rdpsnd->dynamic));
251  return rdpsnd_virtual_channel_write(rdpsnd, pdu);
252 }
253 
259 static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s)
260 {
261  UINT16 wNumberOfFormats = 0;
262  UINT ret = ERROR_BAD_LENGTH;
263 
264  WINPR_ASSERT(rdpsnd);
265  audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
266  rdpsnd->NumberOfServerFormats = 0;
267  rdpsnd->ServerFormats = NULL;
268 
269  if (!Stream_CheckAndLogRequiredLength(TAG, s, 30))
270  return ERROR_BAD_LENGTH;
271 
272  /* http://msdn.microsoft.com/en-us/library/cc240956.aspx */
273  Stream_Seek_UINT32(s); /* dwFlags */
274  Stream_Seek_UINT32(s); /* dwVolume */
275  Stream_Seek_UINT32(s); /* dwPitch */
276  Stream_Seek_UINT16(s); /* wDGramPort */
277  Stream_Read_UINT16(s, wNumberOfFormats);
278  Stream_Read_UINT8(s, rdpsnd->cBlockNo); /* cLastBlockConfirmed */
279  Stream_Read_UINT16(s, rdpsnd->wVersion); /* wVersion */
280  Stream_Seek_UINT8(s); /* bPad */
281  rdpsnd->NumberOfServerFormats = wNumberOfFormats;
282 
283  if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, wNumberOfFormats, 14ull))
284  return ERROR_BAD_LENGTH;
285 
286  if (rdpsnd->NumberOfServerFormats > 0)
287  {
288  rdpsnd->ServerFormats = audio_formats_new(wNumberOfFormats);
289 
290  if (!rdpsnd->ServerFormats)
291  return CHANNEL_RC_NO_MEMORY;
292 
293  for (UINT16 index = 0; index < wNumberOfFormats; index++)
294  {
295  AUDIO_FORMAT* format = &rdpsnd->ServerFormats[index];
296 
297  if (!audio_format_read(s, format))
298  goto out_fail;
299  }
300  }
301 
302  WINPR_ASSERT(rdpsnd->device);
303  ret = IFCALLRESULT(CHANNEL_RC_OK, rdpsnd->device->ServerFormatAnnounce, rdpsnd->device,
304  rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
305  if (ret != CHANNEL_RC_OK)
306  goto out_fail;
307 
308  rdpsnd_select_supported_audio_formats(rdpsnd);
309  WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Server Audio Formats",
310  rdpsnd_is_dyn_str(rdpsnd->dynamic));
311  ret = rdpsnd_send_client_audio_formats(rdpsnd);
312 
313  if (ret == CHANNEL_RC_OK)
314  {
315  if (rdpsnd->wVersion >= CHANNEL_VERSION_WIN_7)
316  ret = rdpsnd_send_quality_mode_pdu(rdpsnd);
317  }
318 
319  return ret;
320 out_fail:
321  audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
322  rdpsnd->ServerFormats = NULL;
323  rdpsnd->NumberOfServerFormats = 0;
324  return ret;
325 }
326 
332 static UINT rdpsnd_send_training_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp,
333  UINT16 wPackSize)
334 {
335  wStream* pdu = NULL;
336  WINPR_ASSERT(rdpsnd);
337  pdu = Stream_New(NULL, 8);
338 
339  if (!pdu)
340  {
341  WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic));
342  return CHANNEL_RC_NO_MEMORY;
343  }
344 
345  Stream_Write_UINT8(pdu, SNDC_TRAINING); /* msgType */
346  Stream_Write_UINT8(pdu, 0); /* bPad */
347  Stream_Write_UINT16(pdu, 4); /* BodySize */
348  Stream_Write_UINT16(pdu, wTimeStamp);
349  Stream_Write_UINT16(pdu, wPackSize);
350  WLog_Print(rdpsnd->log, WLOG_DEBUG,
351  "%s Training Response: wTimeStamp: %" PRIu16 " wPackSize: %" PRIu16 "",
352  rdpsnd_is_dyn_str(rdpsnd->dynamic), wTimeStamp, wPackSize);
353  return rdpsnd_virtual_channel_write(rdpsnd, pdu);
354 }
355 
361 static UINT rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s)
362 {
363  UINT16 wTimeStamp = 0;
364  UINT16 wPackSize = 0;
365  WINPR_ASSERT(rdpsnd);
366  WINPR_ASSERT(s);
367 
368  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
369  return ERROR_BAD_LENGTH;
370 
371  Stream_Read_UINT16(s, wTimeStamp);
372  Stream_Read_UINT16(s, wPackSize);
373  WLog_Print(rdpsnd->log, WLOG_DEBUG,
374  "%s Training Request: wTimeStamp: %" PRIu16 " wPackSize: %" PRIu16 "",
375  rdpsnd_is_dyn_str(rdpsnd->dynamic), wTimeStamp, wPackSize);
376  return rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize);
377 }
378 
379 static BOOL rdpsnd_apply_volume(rdpsndPlugin* rdpsnd)
380 {
381  WINPR_ASSERT(rdpsnd);
382 
383  if (rdpsnd->isOpen && rdpsnd->applyVolume && rdpsnd->device)
384  {
385  BOOL rc = IFCALLRESULT(TRUE, rdpsnd->device->SetVolume, rdpsnd->device, rdpsnd->volume);
386  if (!rc)
387  return FALSE;
388  rdpsnd->applyVolume = FALSE;
389  }
390  return TRUE;
391 }
392 
393 static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT16 wFormatNo,
394  const AUDIO_FORMAT* format)
395 {
396  if (!rdpsnd)
397  return FALSE;
398  WINPR_ASSERT(format);
399 
400  if (!rdpsnd->isOpen || (wFormatNo != rdpsnd->wCurrentFormatNo))
401  {
402  BOOL rc = 0;
403  BOOL supported = 0;
404  AUDIO_FORMAT deviceFormat = *format;
405 
406  IFCALL(rdpsnd->device->Close, rdpsnd->device);
407  supported = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format);
408 
409  if (!supported)
410  {
411  if (!IFCALLRESULT(FALSE, rdpsnd->device->DefaultFormat, rdpsnd->device, format,
412  &deviceFormat))
413  {
414  deviceFormat.wFormatTag = WAVE_FORMAT_PCM;
415  deviceFormat.wBitsPerSample = 16;
416  deviceFormat.cbSize = 0;
417  }
418  }
419 
420  WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Opening device with format %s [backend %s]",
421  rdpsnd_is_dyn_str(rdpsnd->dynamic),
422  audio_format_get_tag_string(format->wFormatTag),
423  audio_format_get_tag_string(deviceFormat.wFormatTag));
424  rc = IFCALLRESULT(FALSE, rdpsnd->device->Open, rdpsnd->device, &deviceFormat,
425  rdpsnd->latency);
426 
427  if (!rc)
428  return FALSE;
429 
430  if (!supported)
431  {
432  if (!freerdp_dsp_context_reset(rdpsnd->dsp_context, format, 0u))
433  return FALSE;
434  }
435 
436  rdpsnd->isOpen = TRUE;
437  rdpsnd->wCurrentFormatNo = wFormatNo;
438  rdpsnd->startPlayTime = 0;
439  rdpsnd->totalPlaySize = 0;
440  }
441 
442  return rdpsnd_apply_volume(rdpsnd);
443 }
444 
450 static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodySize)
451 {
452  UINT16 wFormatNo = 0;
453  const AUDIO_FORMAT* format = NULL;
454  WINPR_ASSERT(rdpsnd);
455  WINPR_ASSERT(s);
456 
457  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
458  return ERROR_BAD_LENGTH;
459 
460  rdpsnd->wArrivalTime = GetTickCount64();
461  Stream_Read_UINT16(s, rdpsnd->wTimeStamp);
462  Stream_Read_UINT16(s, wFormatNo);
463 
464  if (wFormatNo >= rdpsnd->NumberOfClientFormats)
465  return ERROR_INVALID_DATA;
466 
467  Stream_Read_UINT8(s, rdpsnd->cBlockNo);
468  Stream_Seek(s, 3); /* bPad */
469  Stream_Read(s, rdpsnd->waveData, 4);
470  rdpsnd->waveDataSize = BodySize - 8;
471  format = &rdpsnd->ClientFormats[wFormatNo];
472  WLog_Print(rdpsnd->log, WLOG_DEBUG,
473  "%s WaveInfo: cBlockNo: %" PRIu8 " wFormatNo: %" PRIu16 " [%s]",
474  rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, wFormatNo,
475  audio_format_get_tag_string(format->wFormatTag));
476 
477  if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format))
478  return ERROR_INTERNAL_ERROR;
479 
480  rdpsnd->expectingWave = TRUE;
481  return CHANNEL_RC_OK;
482 }
483 
489 static UINT rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, UINT16 wTimeStamp,
490  BYTE cConfirmedBlockNo)
491 {
492  wStream* pdu = NULL;
493  WINPR_ASSERT(rdpsnd);
494  pdu = Stream_New(NULL, 8);
495 
496  if (!pdu)
497  {
498  WLog_ERR(TAG, "%s Stream_New failed!", rdpsnd_is_dyn_str(rdpsnd->dynamic));
499  return CHANNEL_RC_NO_MEMORY;
500  }
501 
502  Stream_Write_UINT8(pdu, SNDC_WAVECONFIRM);
503  Stream_Write_UINT8(pdu, 0);
504  Stream_Write_UINT16(pdu, 4);
505  Stream_Write_UINT16(pdu, wTimeStamp);
506  Stream_Write_UINT8(pdu, cConfirmedBlockNo); /* cConfirmedBlockNo */
507  Stream_Write_UINT8(pdu, 0); /* bPad */
508  return rdpsnd_virtual_channel_write(rdpsnd, pdu);
509 }
510 
511 static BOOL rdpsnd_detect_overrun(rdpsndPlugin* rdpsnd, const AUDIO_FORMAT* format, size_t size)
512 {
513  UINT32 bpf = 0;
514  UINT32 now = 0;
515  UINT32 duration = 0;
516  UINT32 totalDuration = 0;
517  UINT32 remainingDuration = 0;
518  UINT32 maxDuration = 0;
519 
520  if (!rdpsnd || !format)
521  return FALSE;
522 
523  /* Older windows RDP servers do not limit the send buffer, which can
524  * cause quite a large amount of sound data buffered client side.
525  * If e.g. sound is paused server side the client will keep playing
526  * for a long time instead of pausing playback.
527  *
528  * To avoid this we check:
529  *
530  * 1. Is the sound sample received from a known format these servers
531  * support
532  * 2. If it is calculate the size of the client side sound buffer
533  * 3. If the buffer is too large silently drop the sample which will
534  * trigger a retransmit later on.
535  *
536  * This check must only be applied to these known formats, because
537  * with newer and other formats the sample size can not be calculated
538  * without decompressing the sample first.
539  */
540  switch (format->wFormatTag)
541  {
542  case WAVE_FORMAT_PCM:
543  case WAVE_FORMAT_DVI_ADPCM:
544  case WAVE_FORMAT_ADPCM:
545  case WAVE_FORMAT_ALAW:
546  case WAVE_FORMAT_MULAW:
547  break;
548  case WAVE_FORMAT_MSG723:
549  case WAVE_FORMAT_GSM610:
550  case WAVE_FORMAT_AAC_MS:
551  default:
552  return FALSE;
553  }
554 
555  audio_format_print(WLog_Get(TAG), WLOG_DEBUG, format);
556  bpf = format->nChannels * format->wBitsPerSample * format->nSamplesPerSec / 8;
557  if (bpf == 0)
558  return FALSE;
559 
560  duration = (UINT32)(1000 * size / bpf);
561  totalDuration = (UINT32)(1000 * rdpsnd->totalPlaySize / bpf);
562  now = GetTickCountPrecise();
563  if (rdpsnd->startPlayTime == 0)
564  {
565  rdpsnd->startPlayTime = now;
566  rdpsnd->totalPlaySize = size;
567  return FALSE;
568  }
569  else if (now - rdpsnd->startPlayTime > totalDuration + 10)
570  {
571  /* Buffer underrun */
572  WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Buffer underrun by %u ms",
573  rdpsnd_is_dyn_str(rdpsnd->dynamic),
574  (UINT)(now - rdpsnd->startPlayTime - totalDuration));
575  rdpsnd->startPlayTime = now;
576  rdpsnd->totalPlaySize = size;
577  return FALSE;
578  }
579  else
580  {
581  /* Calculate remaining duration to be played */
582  remainingDuration = totalDuration - (now - rdpsnd->startPlayTime);
583 
584  /* Maximum allow duration calculation */
585  maxDuration = duration * 2 + rdpsnd->latency;
586 
587  if (remainingDuration + duration > maxDuration)
588  {
589  WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Buffer overrun pending %u ms dropping %u ms",
590  rdpsnd_is_dyn_str(rdpsnd->dynamic), remainingDuration, duration);
591  return TRUE;
592  }
593 
594  rdpsnd->totalPlaySize += size;
595  return FALSE;
596  }
597 }
598 
599 static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size)
600 {
601  AUDIO_FORMAT* format = NULL;
602  UINT64 end = 0;
603  UINT64 diffMS = 0;
604  UINT64 ts = 0;
605  UINT latency = 0;
606  UINT error = 0;
607 
608  if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
609  return ERROR_BAD_LENGTH;
610 
611  if (rdpsnd->wCurrentFormatNo >= rdpsnd->NumberOfClientFormats)
612  return ERROR_INTERNAL_ERROR;
613 
614  /*
615  * Send the first WaveConfirm PDU. The server side uses this to determine the
616  * network latency.
617  * See also [MS-RDPEA] 2.2.3.8 Wave Confirm PDU
618  */
619  error = rdpsnd_send_wave_confirm_pdu(rdpsnd, rdpsnd->wTimeStamp, rdpsnd->cBlockNo);
620  if (error)
621  return error;
622 
623  const BYTE* data = Stream_ConstPointer(s);
624  format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo];
625  WLog_Print(rdpsnd->log, WLOG_DEBUG,
626  "%s Wave: cBlockNo: %" PRIu8 " wTimeStamp: %" PRIu16 ", size: %" PRIdz,
627  rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, rdpsnd->wTimeStamp, size);
628 
629  if (rdpsnd->device && rdpsnd->attached && !rdpsnd_detect_overrun(rdpsnd, format, size))
630  {
631  UINT status = CHANNEL_RC_OK;
632  wStream* pcmData = StreamPool_Take(rdpsnd->pool, 4096);
633 
634  if (rdpsnd->device->FormatSupported(rdpsnd->device, format))
635  {
636  if (rdpsnd->device->PlayEx)
637  latency = rdpsnd->device->PlayEx(rdpsnd->device, format, data, size);
638  else
639  latency = IFCALLRESULT(0, rdpsnd->device->Play, rdpsnd->device, data, size);
640  }
641  else if (freerdp_dsp_decode(rdpsnd->dsp_context, format, data, size, pcmData))
642  {
643  Stream_SealLength(pcmData);
644 
645  if (rdpsnd->device->PlayEx)
646  latency = rdpsnd->device->PlayEx(rdpsnd->device, format, Stream_Buffer(pcmData),
647  Stream_Length(pcmData));
648  else
649  latency = IFCALLRESULT(0, rdpsnd->device->Play, rdpsnd->device,
650  Stream_Buffer(pcmData), Stream_Length(pcmData));
651  }
652  else
653  status = ERROR_INTERNAL_ERROR;
654 
655  Stream_Release(pcmData);
656 
657  if (status != CHANNEL_RC_OK)
658  return status;
659  }
660 
661  end = GetTickCount64();
662  diffMS = end - rdpsnd->wArrivalTime + latency;
663  ts = (rdpsnd->wTimeStamp + diffMS) % UINT16_MAX;
664 
665  /*
666  * Send the second WaveConfirm PDU. With the first WaveConfirm PDU,
667  * the server side uses this second WaveConfirm PDU to determine the actual
668  * render latency.
669  */
670  return rdpsnd_send_wave_confirm_pdu(rdpsnd, (UINT16)ts, rdpsnd->cBlockNo);
671 }
672 
678 static UINT rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s)
679 {
680  rdpsnd->expectingWave = FALSE;
681 
688  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
689  return ERROR_INVALID_DATA;
690 
691  CopyMemory(Stream_Buffer(s), rdpsnd->waveData, 4);
692  return rdpsnd_treat_wave(rdpsnd, s, rdpsnd->waveDataSize);
693 }
694 
695 static UINT rdpsnd_recv_wave2_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodySize)
696 {
697  UINT16 wFormatNo = 0;
698  AUDIO_FORMAT* format = NULL;
699  UINT32 dwAudioTimeStamp = 0;
700 
701  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
702  return ERROR_BAD_LENGTH;
703 
704  Stream_Read_UINT16(s, rdpsnd->wTimeStamp);
705  Stream_Read_UINT16(s, wFormatNo);
706  Stream_Read_UINT8(s, rdpsnd->cBlockNo);
707  Stream_Seek(s, 3); /* bPad */
708  Stream_Read_UINT32(s, dwAudioTimeStamp);
709  if (wFormatNo >= rdpsnd->NumberOfClientFormats)
710  return ERROR_INVALID_DATA;
711  format = &rdpsnd->ClientFormats[wFormatNo];
712  rdpsnd->waveDataSize = BodySize - 12;
713  rdpsnd->wArrivalTime = GetTickCount64();
714  WLog_Print(rdpsnd->log, WLOG_DEBUG,
715  "%s Wave2PDU: cBlockNo: %" PRIu8 " wFormatNo: %" PRIu16 " [%s] , align=%hu",
716  rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, wFormatNo,
717  audio_format_get_tag_string(format->wFormatTag), format->nBlockAlign);
718 
719  if (!rdpsnd_ensure_device_is_open(rdpsnd, wFormatNo, format))
720  return ERROR_INTERNAL_ERROR;
721 
722  return rdpsnd_treat_wave(rdpsnd, s, rdpsnd->waveDataSize);
723 }
724 
725 static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd)
726 {
727  if (rdpsnd->isOpen)
728  {
729  WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Closing device",
730  rdpsnd_is_dyn_str(rdpsnd->dynamic));
731  }
732  else
733  WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Device already closed",
734  rdpsnd_is_dyn_str(rdpsnd->dynamic));
735 }
736 
742 static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s)
743 {
744  BOOL rc = TRUE;
745  UINT32 dwVolume = 0;
746 
747  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
748  return ERROR_BAD_LENGTH;
749 
750  Stream_Read_UINT32(s, dwVolume);
751  WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Volume: 0x%08" PRIX32 "",
752  rdpsnd_is_dyn_str(rdpsnd->dynamic), dwVolume);
753 
754  rdpsnd->volume = dwVolume;
755  rdpsnd->applyVolume = TRUE;
756  rc = rdpsnd_apply_volume(rdpsnd);
757 
758  if (!rc)
759  {
760  WLog_ERR(TAG, "%s error setting volume", rdpsnd_is_dyn_str(rdpsnd->dynamic));
761  return CHANNEL_RC_INITIALIZATION_ERROR;
762  }
763 
764  return CHANNEL_RC_OK;
765 }
766 
772 static UINT rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s)
773 {
774  BYTE msgType = 0;
775  UINT16 BodySize = 0;
776  UINT status = CHANNEL_RC_OK;
777 
778  if (rdpsnd->expectingWave)
779  {
780  status = rdpsnd_recv_wave_pdu(rdpsnd, s);
781  goto out;
782  }
783 
784  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
785  {
786  status = ERROR_BAD_LENGTH;
787  goto out;
788  }
789 
790  Stream_Read_UINT8(s, msgType); /* msgType */
791  Stream_Seek_UINT8(s); /* bPad */
792  Stream_Read_UINT16(s, BodySize);
793 
794  switch (msgType)
795  {
796  case SNDC_FORMATS:
797  status = rdpsnd_recv_server_audio_formats_pdu(rdpsnd, s);
798  break;
799 
800  case SNDC_TRAINING:
801  status = rdpsnd_recv_training_pdu(rdpsnd, s);
802  break;
803 
804  case SNDC_WAVE:
805  status = rdpsnd_recv_wave_info_pdu(rdpsnd, s, BodySize);
806  break;
807 
808  case SNDC_CLOSE:
809  rdpsnd_recv_close_pdu(rdpsnd);
810  break;
811 
812  case SNDC_SETVOLUME:
813  status = rdpsnd_recv_volume_pdu(rdpsnd, s);
814  break;
815 
816  case SNDC_WAVE2:
817  status = rdpsnd_recv_wave2_pdu(rdpsnd, s, BodySize);
818  break;
819 
820  default:
821  WLog_ERR(TAG, "%s unknown msgType %" PRIu8 "", rdpsnd_is_dyn_str(rdpsnd->dynamic),
822  msgType);
823  break;
824  }
825 
826 out:
827  Stream_Release(s);
828  return status;
829 }
830 
831 static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsndDevicePlugin* device)
832 {
833  if (rdpsnd->device)
834  {
835  WLog_ERR(TAG, "%s existing device, abort.", rdpsnd_is_dyn_str(FALSE));
836  return;
837  }
838 
839  rdpsnd->device = device;
840  device->rdpsnd = rdpsnd;
841 }
842 
848 static UINT rdpsnd_load_device_plugin(rdpsndPlugin* rdpsnd, const char* name,
849  const ADDIN_ARGV* args)
850 {
851  FREERDP_RDPSND_DEVICE_ENTRY_POINTS entryPoints = { 0 };
852  UINT error = 0;
853  DWORD flags = FREERDP_ADDIN_CHANNEL_STATIC | FREERDP_ADDIN_CHANNEL_ENTRYEX;
854  if (rdpsnd->dynamic)
855  flags = FREERDP_ADDIN_CHANNEL_DYNAMIC;
856  PVIRTUALCHANNELENTRY pvce =
857  freerdp_load_channel_addin_entry(RDPSND_CHANNEL_NAME, name, NULL, flags);
858  PFREERDP_RDPSND_DEVICE_ENTRY entry = WINPR_FUNC_PTR_CAST(pvce, PFREERDP_RDPSND_DEVICE_ENTRY);
859 
860  if (!entry)
861  return ERROR_INTERNAL_ERROR;
862 
863  entryPoints.rdpsnd = rdpsnd;
864  entryPoints.pRegisterRdpsndDevice = rdpsnd_register_device_plugin;
865  entryPoints.args = args;
866 
867  error = entry(&entryPoints);
868  if (error)
869  WLog_ERR(TAG, "%s %s entry returns error %" PRIu32 "", rdpsnd_is_dyn_str(rdpsnd->dynamic),
870  name, error);
871 
872  WLog_INFO(TAG, "%s Loaded %s backend for rdpsnd", rdpsnd_is_dyn_str(rdpsnd->dynamic), name);
873  return error;
874 }
875 
876 static BOOL rdpsnd_set_subsystem(rdpsndPlugin* rdpsnd, const char* subsystem)
877 {
878  free(rdpsnd->subsystem);
879  rdpsnd->subsystem = _strdup(subsystem);
880  return (rdpsnd->subsystem != NULL);
881 }
882 
883 static BOOL rdpsnd_set_device_name(rdpsndPlugin* rdpsnd, const char* device_name)
884 {
885  free(rdpsnd->device_name);
886  rdpsnd->device_name = _strdup(device_name);
887  return (rdpsnd->device_name != NULL);
888 }
889 
895 static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, const ADDIN_ARGV* args)
896 {
897  int status = 0;
898  DWORD flags = 0;
899  const COMMAND_LINE_ARGUMENT_A* arg = NULL;
900  COMMAND_LINE_ARGUMENT_A rdpsnd_args[] = {
901  { "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "subsystem" },
902  { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "device" },
903  { "format", COMMAND_LINE_VALUE_REQUIRED, "<format>", NULL, NULL, -1, NULL, "format" },
904  { "rate", COMMAND_LINE_VALUE_REQUIRED, "<rate>", NULL, NULL, -1, NULL, "rate" },
905  { "channel", COMMAND_LINE_VALUE_REQUIRED, "<channel>", NULL, NULL, -1, NULL, "channel" },
906  { "latency", COMMAND_LINE_VALUE_REQUIRED, "<latency>", NULL, NULL, -1, NULL, "latency" },
907  { "quality", COMMAND_LINE_VALUE_REQUIRED, "<quality mode>", NULL, NULL, -1, NULL,
908  "quality mode" },
909  { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
910  };
911  rdpsnd->wQualityMode = HIGH_QUALITY; /* default quality mode */
912 
913  if (args->argc > 1)
914  {
915  flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
916  status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_args, flags, rdpsnd,
917  NULL, NULL);
918 
919  if (status < 0)
920  return CHANNEL_RC_INITIALIZATION_ERROR;
921 
922  arg = rdpsnd_args;
923  errno = 0;
924 
925  do
926  {
927  if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
928  continue;
929 
930  CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "sys")
931  {
932  if (!rdpsnd_set_subsystem(rdpsnd, arg->Value))
933  return CHANNEL_RC_NO_MEMORY;
934  }
935  CommandLineSwitchCase(arg, "dev")
936  {
937  if (!rdpsnd_set_device_name(rdpsnd, arg->Value))
938  return CHANNEL_RC_NO_MEMORY;
939  }
940  CommandLineSwitchCase(arg, "format")
941  {
942  unsigned long val = strtoul(arg->Value, NULL, 0);
943 
944  if ((errno != 0) || (val > UINT16_MAX))
945  return CHANNEL_RC_INITIALIZATION_ERROR;
946 
947  rdpsnd->fixed_format->wFormatTag = (UINT16)val;
948  }
949  CommandLineSwitchCase(arg, "rate")
950  {
951  unsigned long val = strtoul(arg->Value, NULL, 0);
952 
953  if ((errno != 0) || (val > UINT32_MAX))
954  return CHANNEL_RC_INITIALIZATION_ERROR;
955 
956  rdpsnd->fixed_format->nSamplesPerSec = (UINT32)val;
957  }
958  CommandLineSwitchCase(arg, "channel")
959  {
960  unsigned long val = strtoul(arg->Value, NULL, 0);
961 
962  if ((errno != 0) || (val > UINT16_MAX))
963  return CHANNEL_RC_INITIALIZATION_ERROR;
964 
965  rdpsnd->fixed_format->nChannels = (UINT16)val;
966  }
967  CommandLineSwitchCase(arg, "latency")
968  {
969  unsigned long val = strtoul(arg->Value, NULL, 0);
970 
971  if ((errno != 0) || (val > UINT32_MAX))
972  return CHANNEL_RC_INITIALIZATION_ERROR;
973 
974  rdpsnd->latency = (UINT32)val;
975  }
976  CommandLineSwitchCase(arg, "quality")
977  {
978  long wQualityMode = DYNAMIC_QUALITY;
979 
980  if (_stricmp(arg->Value, "dynamic") == 0)
981  wQualityMode = DYNAMIC_QUALITY;
982  else if (_stricmp(arg->Value, "medium") == 0)
983  wQualityMode = MEDIUM_QUALITY;
984  else if (_stricmp(arg->Value, "high") == 0)
985  wQualityMode = HIGH_QUALITY;
986  else
987  {
988  wQualityMode = strtol(arg->Value, NULL, 0);
989 
990  if (errno != 0)
991  return CHANNEL_RC_INITIALIZATION_ERROR;
992  }
993 
994  if ((wQualityMode < 0) || (wQualityMode > 2))
995  wQualityMode = DYNAMIC_QUALITY;
996 
997  rdpsnd->wQualityMode = (UINT16)wQualityMode;
998  }
999  CommandLineSwitchDefault(arg)
1000  {
1001  }
1002  CommandLineSwitchEnd(arg)
1003  } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
1004  }
1005 
1006  return CHANNEL_RC_OK;
1007 }
1008 
1014 static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd)
1015 {
1016  const struct
1017  {
1018  const char* subsystem;
1019  const char* device;
1020  } backends[] = {
1021 #if defined(WITH_IOSAUDIO)
1022  { "ios", "" },
1023 #endif
1024 #if defined(WITH_OPENSLES)
1025  { "opensles", "" },
1026 #endif
1027 #if defined(WITH_PULSE)
1028  { "pulse", "" },
1029 #endif
1030 #if defined(WITH_ALSA)
1031  { "alsa", "default" },
1032 #endif
1033 #if defined(WITH_OSS)
1034  { "oss", "" },
1035 #endif
1036 #if defined(WITH_MACAUDIO)
1037  { "mac", "default" },
1038 #endif
1039 #if defined(WITH_WINMM)
1040  { "winmm", "" },
1041 #endif
1042 #if defined(WITH_SNDIO)
1043  { "sndio", "" },
1044 #endif
1045  { "fake", "" }
1046  };
1047  const ADDIN_ARGV* args = NULL;
1048  UINT status = ERROR_INTERNAL_ERROR;
1049  WINPR_ASSERT(rdpsnd);
1050  rdpsnd->latency = 0;
1051  args = (const ADDIN_ARGV*)rdpsnd->channelEntryPoints.pExtendedData;
1052 
1053  if (args)
1054  {
1055  status = rdpsnd_process_addin_args(rdpsnd, args);
1056 
1057  if (status != CHANNEL_RC_OK)
1058  return status;
1059  }
1060 
1061  if (rdpsnd->subsystem)
1062  {
1063  if ((status = rdpsnd_load_device_plugin(rdpsnd, rdpsnd->subsystem, args)))
1064  {
1065  WLog_ERR(TAG,
1066  "%s Unable to load sound playback subsystem %s because of error %" PRIu32 "",
1067  rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->subsystem, status);
1068  return status;
1069  }
1070  }
1071  else
1072  {
1073  for (size_t x = 0; x < ARRAYSIZE(backends); x++)
1074  {
1075  const char* subsystem_name = backends[x].subsystem;
1076  const char* device_name = backends[x].device;
1077 
1078  if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args)))
1079  WLog_ERR(TAG,
1080  "%s Unable to load sound playback subsystem %s because of error %" PRIu32
1081  "",
1082  rdpsnd_is_dyn_str(rdpsnd->dynamic), subsystem_name, status);
1083 
1084  if (!rdpsnd->device)
1085  continue;
1086 
1087  if (!rdpsnd_set_subsystem(rdpsnd, subsystem_name) ||
1088  !rdpsnd_set_device_name(rdpsnd, device_name))
1089  return CHANNEL_RC_NO_MEMORY;
1090 
1091  break;
1092  }
1093 
1094  if (!rdpsnd->device || status)
1095  return CHANNEL_RC_INITIALIZATION_ERROR;
1096  }
1097 
1098  return CHANNEL_RC_OK;
1099 }
1100 
1106 UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s)
1107 {
1108  UINT status = CHANNEL_RC_BAD_INIT_HANDLE;
1109 
1110  if (rdpsnd)
1111  {
1112  if (rdpsnd->dynamic)
1113  {
1114  IWTSVirtualChannel* channel = NULL;
1115  if (rdpsnd->listener_callback)
1116  {
1117  channel = rdpsnd->listener_callback->channel_callback->channel;
1118  status = channel->Write(channel, (UINT32)Stream_Length(s), Stream_Buffer(s), NULL);
1119  }
1120  Stream_Free(s, TRUE);
1121  }
1122  else
1123  {
1124  status = rdpsnd->channelEntryPoints.pVirtualChannelWriteEx(
1125  rdpsnd->InitHandle, rdpsnd->OpenHandle, Stream_Buffer(s),
1126  (UINT32)Stream_GetPosition(s), s);
1127 
1128  if (status != CHANNEL_RC_OK)
1129  {
1130  Stream_Free(s, TRUE);
1131  WLog_ERR(TAG, "%s pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]",
1132  rdpsnd_is_dyn_str(FALSE), WTSErrorToString(status), status);
1133  }
1134  }
1135  }
1136 
1137  return status;
1138 }
1139 
1145 static UINT rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin, void* pData,
1146  UINT32 dataLength, UINT32 totalLength,
1147  UINT32 dataFlags)
1148 {
1149  if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME))
1150  return CHANNEL_RC_OK;
1151 
1152  if (dataFlags & CHANNEL_FLAG_FIRST)
1153  {
1154  if (!plugin->data_in)
1155  plugin->data_in = StreamPool_Take(plugin->pool, totalLength);
1156 
1157  Stream_SetPosition(plugin->data_in, 0);
1158  }
1159 
1160  if (!Stream_EnsureRemainingCapacity(plugin->data_in, dataLength))
1161  return CHANNEL_RC_NO_MEMORY;
1162 
1163  Stream_Write(plugin->data_in, pData, dataLength);
1164 
1165  if (dataFlags & CHANNEL_FLAG_LAST)
1166  {
1167  Stream_SealLength(plugin->data_in);
1168  Stream_SetPosition(plugin->data_in, 0);
1169 
1170  if (plugin->async)
1171  {
1172  if (!MessageQueue_Post(plugin->queue, NULL, 0, plugin->data_in, NULL))
1173  return ERROR_INTERNAL_ERROR;
1174  plugin->data_in = NULL;
1175  }
1176  else
1177  {
1178  UINT error = rdpsnd_recv_pdu(plugin, plugin->data_in);
1179  plugin->data_in = NULL;
1180  if (error)
1181  return error;
1182  }
1183  }
1184 
1185  return CHANNEL_RC_OK;
1186 }
1187 
1188 static VOID VCAPITYPE rdpsnd_virtual_channel_open_event_ex(LPVOID lpUserParam, DWORD openHandle,
1189  UINT event, LPVOID pData,
1190  UINT32 dataLength, UINT32 totalLength,
1191  UINT32 dataFlags)
1192 {
1193  UINT error = CHANNEL_RC_OK;
1194  rdpsndPlugin* rdpsnd = (rdpsndPlugin*)lpUserParam;
1195  WINPR_ASSERT(rdpsnd);
1196  WINPR_ASSERT(!rdpsnd->dynamic);
1197 
1198  switch (event)
1199  {
1200  case CHANNEL_EVENT_DATA_RECEIVED:
1201  if (!rdpsnd)
1202  return;
1203 
1204  if (rdpsnd->OpenHandle != openHandle)
1205  {
1206  WLog_ERR(TAG, "%s error no match", rdpsnd_is_dyn_str(rdpsnd->dynamic));
1207  return;
1208  }
1209  if ((error = rdpsnd_virtual_channel_event_data_received(rdpsnd, pData, dataLength,
1210  totalLength, dataFlags)))
1211  WLog_ERR(TAG,
1212  "%s rdpsnd_virtual_channel_event_data_received failed with error %" PRIu32
1213  "",
1214  rdpsnd_is_dyn_str(rdpsnd->dynamic), error);
1215 
1216  break;
1217 
1218  case CHANNEL_EVENT_WRITE_CANCELLED:
1219  case CHANNEL_EVENT_WRITE_COMPLETE:
1220  {
1221  wStream* s = (wStream*)pData;
1222  Stream_Free(s, TRUE);
1223  }
1224  break;
1225 
1226  case CHANNEL_EVENT_USER:
1227  break;
1228  default:
1229  break;
1230  }
1231 
1232  if (error && rdpsnd && rdpsnd->rdpcontext)
1233  {
1234  char buffer[8192];
1235  (void)_snprintf(buffer, sizeof(buffer),
1236  "%s rdpsnd_virtual_channel_open_event_ex reported an error",
1237  rdpsnd_is_dyn_str(rdpsnd->dynamic));
1238  setChannelError(rdpsnd->rdpcontext, error, buffer);
1239  }
1240 }
1241 
1247 static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, LPVOID pData,
1248  UINT32 dataLength)
1249 {
1250  UINT32 status = 0;
1251  DWORD opened = 0;
1252  WINPR_UNUSED(pData);
1253  WINPR_UNUSED(dataLength);
1254 
1255  WINPR_ASSERT(rdpsnd);
1256  WINPR_ASSERT(!rdpsnd->dynamic);
1257 
1258  status = rdpsnd->channelEntryPoints.pVirtualChannelOpenEx(
1259  rdpsnd->InitHandle, &opened, rdpsnd->channelDef.name, rdpsnd_virtual_channel_open_event_ex);
1260 
1261  if (status != CHANNEL_RC_OK)
1262  {
1263  WLog_ERR(TAG, "%s pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]",
1264  rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(status), status);
1265  goto fail;
1266  }
1267 
1268  if (rdpsnd_process_connect(rdpsnd) != CHANNEL_RC_OK)
1269  goto fail;
1270 
1271  rdpsnd->OpenHandle = opened;
1272  return CHANNEL_RC_OK;
1273 fail:
1274  if (opened != 0)
1275  rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, opened);
1276  return CHANNEL_RC_NO_MEMORY;
1277 }
1278 
1279 static void cleanup_internals(rdpsndPlugin* rdpsnd)
1280 {
1281  if (!rdpsnd)
1282  return;
1283 
1284  if (rdpsnd->pool)
1285  StreamPool_Return(rdpsnd->pool, rdpsnd->data_in);
1286 
1287  audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats);
1288  audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats);
1289 
1290  rdpsnd->NumberOfClientFormats = 0;
1291  rdpsnd->ClientFormats = NULL;
1292  rdpsnd->NumberOfServerFormats = 0;
1293  rdpsnd->ServerFormats = NULL;
1294 
1295  rdpsnd->data_in = NULL;
1296 }
1297 
1303 static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd)
1304 {
1305  UINT error = 0;
1306 
1307  WINPR_ASSERT(rdpsnd);
1308  WINPR_ASSERT(!rdpsnd->dynamic);
1309  if (rdpsnd->OpenHandle != 0)
1310  {
1311  DWORD opened = rdpsnd->OpenHandle;
1312  rdpsnd->OpenHandle = 0;
1313  if (rdpsnd->device)
1314  IFCALL(rdpsnd->device->Close, rdpsnd->device);
1315 
1316  error = rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, opened);
1317 
1318  if (CHANNEL_RC_OK != error)
1319  {
1320  WLog_ERR(TAG, "%s pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]",
1321  rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(error), error);
1322  return error;
1323  }
1324  }
1325 
1326  cleanup_internals(rdpsnd);
1327 
1328  if (rdpsnd->device)
1329  {
1330  IFCALL(rdpsnd->device->Free, rdpsnd->device);
1331  rdpsnd->device = NULL;
1332  }
1333 
1334  return CHANNEL_RC_OK;
1335 }
1336 
1337 static void queue_free(void* obj)
1338 {
1339  wMessage* msg = obj;
1340  if (!msg)
1341  return;
1342  if (msg->id != 0)
1343  return;
1344  wStream* s = msg->wParam;
1345  Stream_Release(s);
1346 }
1347 
1348 static void free_internals(rdpsndPlugin* rdpsnd)
1349 {
1350  if (!rdpsnd)
1351  return;
1352 
1353  if (rdpsnd->references > 0)
1354  rdpsnd->references--;
1355 
1356  if (rdpsnd->references > 0)
1357  return;
1358 
1359  freerdp_dsp_context_free(rdpsnd->dsp_context);
1360  StreamPool_Free(rdpsnd->pool);
1361  rdpsnd->pool = NULL;
1362  rdpsnd->dsp_context = NULL;
1363 }
1364 
1365 static BOOL allocate_internals(rdpsndPlugin* rdpsnd)
1366 {
1367  WINPR_ASSERT(rdpsnd);
1368 
1369  if (!rdpsnd->pool)
1370  {
1371  rdpsnd->pool = StreamPool_New(TRUE, 4096);
1372  if (!rdpsnd->pool)
1373  return FALSE;
1374  }
1375 
1376  if (!rdpsnd->dsp_context)
1377  {
1378  rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE);
1379  if (!rdpsnd->dsp_context)
1380  return FALSE;
1381  }
1382  rdpsnd->references++;
1383 
1384  return TRUE;
1385 }
1386 
1387 static DWORD WINAPI play_thread(LPVOID arg)
1388 {
1389  UINT error = CHANNEL_RC_OK;
1390  rdpsndPlugin* rdpsnd = arg;
1391 
1392  if (!rdpsnd || !rdpsnd->queue)
1393  return ERROR_INVALID_PARAMETER;
1394 
1395  while (TRUE)
1396  {
1397  int rc = -1;
1398  wMessage message = { 0 };
1399  wStream* s = NULL;
1400  DWORD status = 0;
1401  DWORD nCount = 0;
1402  HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 };
1403 
1404  handles[nCount++] = MessageQueue_Event(rdpsnd->queue);
1405  handles[nCount++] = freerdp_abort_event(rdpsnd->rdpcontext);
1406  status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE);
1407  switch (status)
1408  {
1409  case WAIT_OBJECT_0:
1410  break;
1411  default:
1412  return ERROR_TIMEOUT;
1413  }
1414 
1415  rc = MessageQueue_Peek(rdpsnd->queue, &message, TRUE);
1416  if (rc < 1)
1417  continue;
1418 
1419  if (message.id == WMQ_QUIT)
1420  break;
1421 
1422  s = message.wParam;
1423  error = rdpsnd_recv_pdu(rdpsnd, s);
1424 
1425  if (error)
1426  return error;
1427  }
1428 
1429  return CHANNEL_RC_OK;
1430 }
1431 
1432 static UINT rdpsnd_virtual_channel_event_initialized(rdpsndPlugin* rdpsnd)
1433 {
1434  if (!rdpsnd)
1435  return ERROR_INVALID_PARAMETER;
1436 
1437  if (rdpsnd->async)
1438  {
1439  wObject obj = { 0 };
1440 
1441  obj.fnObjectFree = queue_free;
1442  rdpsnd->queue = MessageQueue_New(&obj);
1443  if (!rdpsnd->queue)
1444  return CHANNEL_RC_NO_MEMORY;
1445 
1446  rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL);
1447  if (!rdpsnd->thread)
1448  return CHANNEL_RC_INITIALIZATION_ERROR;
1449  }
1450 
1451  if (!allocate_internals(rdpsnd))
1452  return CHANNEL_RC_NO_MEMORY;
1453 
1454  return CHANNEL_RC_OK;
1455 }
1456 
1457 void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd)
1458 {
1459  if (rdpsnd)
1460  {
1461  if (rdpsnd->queue)
1462  MessageQueue_PostQuit(rdpsnd->queue, 0);
1463 
1464  if (rdpsnd->thread)
1465  {
1466  (void)WaitForSingleObject(rdpsnd->thread, INFINITE);
1467  (void)CloseHandle(rdpsnd->thread);
1468  }
1469  MessageQueue_Free(rdpsnd->queue);
1470 
1471  free_internals(rdpsnd);
1472  audio_formats_free(rdpsnd->fixed_format, 1);
1473  free(rdpsnd->subsystem);
1474  free(rdpsnd->device_name);
1475  rdpsnd->InitHandle = 0;
1476  }
1477 
1478  free(rdpsnd);
1479 }
1480 
1481 static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle,
1482  UINT event, LPVOID pData,
1483  UINT dataLength)
1484 {
1485  UINT error = CHANNEL_RC_OK;
1486  rdpsndPlugin* plugin = (rdpsndPlugin*)lpUserParam;
1487 
1488  if (!plugin)
1489  return;
1490 
1491  if (plugin->InitHandle != pInitHandle)
1492  {
1493  WLog_ERR(TAG, "%s error no match", rdpsnd_is_dyn_str(plugin->dynamic));
1494  return;
1495  }
1496 
1497  switch (event)
1498  {
1499  case CHANNEL_EVENT_INITIALIZED:
1500  error = rdpsnd_virtual_channel_event_initialized(plugin);
1501  break;
1502 
1503  case CHANNEL_EVENT_CONNECTED:
1504  error = rdpsnd_virtual_channel_event_connected(plugin, pData, dataLength);
1505  break;
1506 
1507  case CHANNEL_EVENT_DISCONNECTED:
1508  error = rdpsnd_virtual_channel_event_disconnected(plugin);
1509  break;
1510 
1511  case CHANNEL_EVENT_TERMINATED:
1512  rdpsnd_virtual_channel_event_terminated(plugin);
1513  plugin = NULL;
1514  break;
1515 
1516  case CHANNEL_EVENT_ATTACHED:
1517  plugin->attached = TRUE;
1518  break;
1519 
1520  case CHANNEL_EVENT_DETACHED:
1521  plugin->attached = FALSE;
1522  break;
1523 
1524  default:
1525  break;
1526  }
1527 
1528  if (error && plugin && plugin->rdpcontext)
1529  {
1530  char buffer[8192];
1531  (void)_snprintf(buffer, sizeof(buffer), "%s reported an error",
1532  rdpsnd_is_dyn_str(plugin->dynamic));
1533  setChannelError(plugin->rdpcontext, error, buffer);
1534  }
1535 }
1536 
1537 rdpContext* freerdp_rdpsnd_get_context(rdpsndPlugin* plugin)
1538 {
1539  if (!plugin)
1540  return NULL;
1541 
1542  return plugin->rdpcontext;
1543 }
1544 
1545 static rdpsndPlugin* allocatePlugin(void)
1546 {
1547  rdpsndPlugin* rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin));
1548  if (!rdpsnd)
1549  goto fail;
1550 
1551  rdpsnd->fixed_format = audio_format_new();
1552  if (!rdpsnd->fixed_format)
1553  goto fail;
1554  rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client");
1555  if (!rdpsnd->log)
1556  goto fail;
1557 
1558  rdpsnd->attached = TRUE;
1559  return rdpsnd;
1560 
1561 fail:
1562  if (rdpsnd)
1563  audio_format_free(rdpsnd->fixed_format);
1564  free(rdpsnd);
1565  return NULL;
1566 }
1567 /* rdpsnd is always built-in */
1568 FREERDP_ENTRY_POINT(BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints,
1569  PVOID pInitHandle))
1570 {
1571  UINT rc = 0;
1572  rdpsndPlugin* rdpsnd = NULL;
1573  CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx = NULL;
1574 
1575  if (!pEntryPoints)
1576  return FALSE;
1577 
1578  rdpsnd = allocatePlugin();
1579 
1580  if (!rdpsnd)
1581  return FALSE;
1582 
1583  rdpsnd->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP;
1584  (void)sprintf_s(rdpsnd->channelDef.name, ARRAYSIZE(rdpsnd->channelDef.name),
1585  RDPSND_CHANNEL_NAME);
1586  pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints;
1587 
1588  if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)) &&
1589  (pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
1590  {
1591  rdpsnd->rdpcontext = pEntryPointsEx->context;
1592  if (!freerdp_settings_get_bool(rdpsnd->rdpcontext->settings,
1593  FreeRDP_SynchronousStaticChannels))
1594  rdpsnd->async = TRUE;
1595  }
1596 
1597  CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints,
1599  rdpsnd->InitHandle = pInitHandle;
1600 
1601  WINPR_ASSERT(rdpsnd->channelEntryPoints.pVirtualChannelInitEx);
1602  rc = rdpsnd->channelEntryPoints.pVirtualChannelInitEx(
1603  rdpsnd, NULL, pInitHandle, &rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000,
1604  rdpsnd_virtual_channel_init_event_ex);
1605 
1606  if (CHANNEL_RC_OK != rc)
1607  {
1608  WLog_ERR(TAG, "%s pVirtualChannelInitEx failed with %s [%08" PRIX32 "]",
1609  rdpsnd_is_dyn_str(FALSE), WTSErrorToString(rc), rc);
1610  rdpsnd_virtual_channel_event_terminated(rdpsnd);
1611  return FALSE;
1612  }
1613 
1614  return TRUE;
1615 }
1616 
1617 static UINT rdpsnd_on_open(IWTSVirtualChannelCallback* pChannelCallback)
1618 {
1619  GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
1620  rdpsndPlugin* rdpsnd = NULL;
1621 
1622  WINPR_ASSERT(callback);
1623 
1624  rdpsnd = (rdpsndPlugin*)callback->plugin;
1625  WINPR_ASSERT(rdpsnd);
1626 
1627  if (rdpsnd->OnOpenCalled)
1628  return CHANNEL_RC_OK;
1629  rdpsnd->OnOpenCalled = TRUE;
1630 
1631  if (!allocate_internals(rdpsnd))
1632  return ERROR_OUTOFMEMORY;
1633 
1634  return rdpsnd_process_connect(rdpsnd);
1635 }
1636 
1637 static UINT rdpsnd_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
1638 {
1639  GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
1640  rdpsndPlugin* plugin = NULL;
1641  wStream* copy = NULL;
1642  size_t len = 0;
1643 
1644  len = Stream_GetRemainingLength(data);
1645 
1646  if (!callback || !callback->plugin)
1647  return ERROR_INVALID_PARAMETER;
1648  plugin = (rdpsndPlugin*)callback->plugin;
1649  WINPR_ASSERT(plugin);
1650 
1651  copy = StreamPool_Take(plugin->pool, len);
1652  if (!copy)
1653  return ERROR_OUTOFMEMORY;
1654  Stream_Copy(data, copy, len);
1655  Stream_SealLength(copy);
1656  Stream_SetPosition(copy, 0);
1657 
1658  if (plugin->async)
1659  {
1660  if (!MessageQueue_Post(plugin->queue, NULL, 0, copy, NULL))
1661  {
1662  Stream_Release(copy);
1663  return ERROR_INTERNAL_ERROR;
1664  }
1665  }
1666  else
1667  {
1668  UINT error = rdpsnd_recv_pdu(plugin, copy);
1669  if (error)
1670  return error;
1671  }
1672 
1673  return CHANNEL_RC_OK;
1674 }
1675 
1676 static UINT rdpsnd_on_close(IWTSVirtualChannelCallback* pChannelCallback)
1677 {
1678  GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
1679  rdpsndPlugin* rdpsnd = NULL;
1680 
1681  WINPR_ASSERT(callback);
1682 
1683  rdpsnd = (rdpsndPlugin*)callback->plugin;
1684  WINPR_ASSERT(rdpsnd);
1685 
1686  rdpsnd->OnOpenCalled = FALSE;
1687  if (rdpsnd->device)
1688  IFCALL(rdpsnd->device->Close, rdpsnd->device);
1689 
1690  cleanup_internals(rdpsnd);
1691 
1692  if (rdpsnd->device)
1693  {
1694  IFCALL(rdpsnd->device->Free, rdpsnd->device);
1695  rdpsnd->device = NULL;
1696  }
1697 
1698  free_internals(rdpsnd);
1699  free(pChannelCallback);
1700  return CHANNEL_RC_OK;
1701 }
1702 
1703 // NOLINTBEGIN(readability-non-const-parameter)
1704 static UINT rdpsnd_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
1705  IWTSVirtualChannel* pChannel, BYTE* Data,
1706  BOOL* pbAccept,
1707  IWTSVirtualChannelCallback** ppCallback)
1708 // NOLINTEND(readability-non-const-parameter)
1709 {
1710  GENERIC_CHANNEL_CALLBACK* callback = NULL;
1711  GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
1712  WINPR_ASSERT(listener_callback);
1713  WINPR_ASSERT(pChannel);
1714  WINPR_ASSERT(ppCallback);
1715  callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
1716 
1717  WINPR_UNUSED(Data);
1718  WINPR_UNUSED(pbAccept);
1719 
1720  if (!callback)
1721  {
1722  WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE));
1723  return CHANNEL_RC_NO_MEMORY;
1724  }
1725 
1726  callback->iface.OnOpen = rdpsnd_on_open;
1727  callback->iface.OnDataReceived = rdpsnd_on_data_received;
1728  callback->iface.OnClose = rdpsnd_on_close;
1729  callback->plugin = listener_callback->plugin;
1730  callback->channel_mgr = listener_callback->channel_mgr;
1731  callback->channel = pChannel;
1732  listener_callback->channel_callback = callback;
1733  *ppCallback = &callback->iface;
1734  return CHANNEL_RC_OK;
1735 }
1736 
1737 static UINT rdpsnd_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
1738 {
1739  UINT status = 0;
1740  rdpsndPlugin* rdpsnd = (rdpsndPlugin*)pPlugin;
1741  WINPR_ASSERT(rdpsnd);
1742  WINPR_ASSERT(pChannelMgr);
1743  if (rdpsnd->initialized)
1744  {
1745  WLog_ERR(TAG, "[%s] channel initialized twice, aborting", RDPSND_DVC_CHANNEL_NAME);
1746  return ERROR_INVALID_DATA;
1747  }
1748  rdpsnd->listener_callback =
1750 
1751  if (!rdpsnd->listener_callback)
1752  {
1753  WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE));
1754  return CHANNEL_RC_NO_MEMORY;
1755  }
1756 
1757  rdpsnd->listener_callback->iface.OnNewChannelConnection = rdpsnd_on_new_channel_connection;
1758  rdpsnd->listener_callback->plugin = pPlugin;
1759  rdpsnd->listener_callback->channel_mgr = pChannelMgr;
1760  status = pChannelMgr->CreateListener(pChannelMgr, RDPSND_DVC_CHANNEL_NAME, 0,
1761  &rdpsnd->listener_callback->iface, &(rdpsnd->listener));
1762  if (status != CHANNEL_RC_OK)
1763  {
1764  WLog_ERR(TAG, "%s CreateListener failed!", rdpsnd_is_dyn_str(TRUE));
1765  return status;
1766  }
1767 
1768  rdpsnd->listener->pInterface = rdpsnd->iface.pInterface;
1769  status = rdpsnd_virtual_channel_event_initialized(rdpsnd);
1770 
1771  rdpsnd->initialized = status == CHANNEL_RC_OK;
1772  return status;
1773 }
1774 
1780 static UINT rdpsnd_plugin_terminated(IWTSPlugin* pPlugin)
1781 {
1782  rdpsndPlugin* rdpsnd = (rdpsndPlugin*)pPlugin;
1783  if (rdpsnd)
1784  {
1785  if (rdpsnd->listener_callback)
1786  {
1787  IWTSVirtualChannelManager* mgr = rdpsnd->listener_callback->channel_mgr;
1788  if (mgr)
1789  IFCALL(mgr->DestroyListener, mgr, rdpsnd->listener);
1790  }
1791  free(rdpsnd->listener_callback);
1792  free(rdpsnd->iface.pInterface);
1793  }
1794  rdpsnd_virtual_channel_event_terminated(rdpsnd);
1795  return CHANNEL_RC_OK;
1796 }
1797 
1803 FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpsnd_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
1804 {
1805  UINT error = CHANNEL_RC_OK;
1806  rdpsndPlugin* rdpsnd = NULL;
1807 
1808  WINPR_ASSERT(pEntryPoints);
1809  WINPR_ASSERT(pEntryPoints->GetPlugin);
1810 
1811  rdpsnd = (rdpsndPlugin*)pEntryPoints->GetPlugin(pEntryPoints, RDPSND_CHANNEL_NAME);
1812 
1813  if (!rdpsnd)
1814  {
1815  IWTSPlugin* iface = NULL;
1816  union
1817  {
1818  const void* cev;
1819  void* ev;
1820  } cnv;
1821 
1822  rdpsnd = allocatePlugin();
1823  if (!rdpsnd)
1824  {
1825  WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE));
1826  return CHANNEL_RC_NO_MEMORY;
1827  }
1828 
1829  iface = &rdpsnd->iface;
1830  iface->Initialize = rdpsnd_plugin_initialize;
1831  iface->Connected = NULL;
1832  iface->Disconnected = NULL;
1833  iface->Terminated = rdpsnd_plugin_terminated;
1834 
1835  rdpsnd->dynamic = TRUE;
1836 
1837  WINPR_ASSERT(pEntryPoints->GetRdpContext);
1838  rdpsnd->rdpcontext = pEntryPoints->GetRdpContext(pEntryPoints);
1839 
1840  if (!freerdp_settings_get_bool(rdpsnd->rdpcontext->settings,
1841  FreeRDP_SynchronousDynamicChannels))
1842  rdpsnd->async = TRUE;
1843 
1844  /* user data pointer is not const, cast to avoid warning. */
1845  cnv.cev = pEntryPoints->GetPluginData(pEntryPoints);
1846  WINPR_ASSERT(pEntryPoints->GetPluginData);
1847  rdpsnd->channelEntryPoints.pExtendedData = cnv.ev;
1848 
1849  error = pEntryPoints->RegisterPlugin(pEntryPoints, RDPSND_CHANNEL_NAME, iface);
1850  }
1851  else
1852  {
1853  WLog_ERR(TAG, "%s could not get rdpsnd Plugin.", rdpsnd_is_dyn_str(TRUE));
1854  return CHANNEL_RC_BAD_CHANNEL;
1855  }
1856 
1857  return error;
1858 }
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
Definition: svc.h:61
Definition: client/rdpsnd.h:76
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57