FreeRDP
server/rdpsnd_main.c
1 
22 #include <freerdp/config.h>
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include <winpr/crt.h>
29 #include <winpr/assert.h>
30 #include <winpr/cast.h>
31 #include <winpr/print.h>
32 #include <winpr/stream.h>
33 
34 #include <freerdp/freerdp.h>
35 #include <freerdp/channels/log.h>
36 
37 #include "rdpsnd_common.h"
38 #include "rdpsnd_main.h"
39 
40 static wStream* rdpsnd_server_get_buffer(RdpsndServerContext* context)
41 {
42  wStream* s = NULL;
43  WINPR_ASSERT(context);
44  WINPR_ASSERT(context->priv);
45 
46  s = context->priv->rdpsnd_pdu;
47  Stream_SetPosition(s, 0);
48  return s;
49 }
50 
56 static UINT rdpsnd_server_send_formats(RdpsndServerContext* context)
57 {
58  wStream* s = rdpsnd_server_get_buffer(context);
59  BOOL status = FALSE;
60  ULONG written = 0;
61 
62  if (!Stream_EnsureRemainingCapacity(s, 24))
63  return ERROR_OUTOFMEMORY;
64 
65  Stream_Write_UINT8(s, SNDC_FORMATS);
66  Stream_Write_UINT8(s, 0);
67  Stream_Seek_UINT16(s);
68  Stream_Write_UINT32(s, 0); /* dwFlags */
69  Stream_Write_UINT32(s, 0); /* dwVolume */
70  Stream_Write_UINT32(s, 0); /* dwPitch */
71  Stream_Write_UINT16(s, 0); /* wDGramPort */
72  Stream_Write_UINT16(
73  s, WINPR_ASSERTING_INT_CAST(uint16_t, context->num_server_formats)); /* wNumberOfFormats */
74  Stream_Write_UINT8(s, context->block_no); /* cLastBlockConfirmed */
75  Stream_Write_UINT16(s, CHANNEL_VERSION_WIN_MAX); /* wVersion */
76  Stream_Write_UINT8(s, 0); /* bPad */
77 
78  for (size_t i = 0; i < context->num_server_formats; i++)
79  {
80  const AUDIO_FORMAT* format = &context->server_formats[i];
81 
82  if (!audio_format_write(s, format))
83  goto fail;
84  }
85 
86  const size_t pos = Stream_GetPosition(s);
87  if (pos > UINT16_MAX)
88  goto fail;
89 
90  WINPR_ASSERT(pos >= 4);
91  Stream_SetPosition(s, 2);
92  Stream_Write_UINT16(s, (UINT16)(pos - 4));
93  Stream_SetPosition(s, pos);
94 
95  WINPR_ASSERT(context->priv);
96 
97  status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
98  (UINT32)pos, &written);
99  Stream_SetPosition(s, 0);
100 fail:
101  return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
102 }
103 
109 static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream* s)
110 {
111  UINT16 timestamp = 0;
112  BYTE confirmBlockNum = 0;
113  UINT error = CHANNEL_RC_OK;
114 
115  WINPR_ASSERT(context);
116 
117  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
118  return ERROR_INVALID_DATA;
119 
120  Stream_Read_UINT16(s, timestamp);
121  Stream_Read_UINT8(s, confirmBlockNum);
122  Stream_Seek_UINT8(s);
123  IFCALLRET(context->ConfirmBlock, error, context, confirmBlockNum, timestamp);
124 
125  if (error)
126  WLog_ERR(TAG, "context->ConfirmBlock failed with error %" PRIu32 "", error);
127 
128  return error;
129 }
130 
136 static UINT rdpsnd_server_recv_trainingconfirm(RdpsndServerContext* context, wStream* s)
137 {
138  UINT16 timestamp = 0;
139  UINT16 packsize = 0;
140  UINT error = CHANNEL_RC_OK;
141 
142  WINPR_ASSERT(context);
143 
144  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
145  return ERROR_INVALID_DATA;
146 
147  Stream_Read_UINT16(s, timestamp);
148  Stream_Read_UINT16(s, packsize);
149 
150  IFCALLRET(context->TrainingConfirm, error, context, timestamp, packsize);
151  if (error)
152  WLog_ERR(TAG, "context->TrainingConfirm failed with error %" PRIu32 "", error);
153 
154  return error;
155 }
156 
162 static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s)
163 {
164  WINPR_ASSERT(context);
165 
166  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
167  {
168  WLog_ERR(TAG, "not enough data in stream!");
169  return ERROR_INVALID_DATA;
170  }
171 
172  Stream_Read_UINT16(s, context->qualityMode); /* wQualityMode */
173  Stream_Seek_UINT16(s); /* Reserved */
174 
175  WLog_DBG(TAG, "Client requested sound quality: 0x%04" PRIX16 "", context->qualityMode);
176 
177  return CHANNEL_RC_OK;
178 }
179 
185 static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s)
186 {
187  UINT16 num_known_format = 0;
188  UINT16 udpPort = 0;
189  BYTE lastblock = 0;
190  UINT error = CHANNEL_RC_OK;
191 
192  WINPR_ASSERT(context);
193 
194  if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
195  return ERROR_INVALID_DATA;
196 
197  Stream_Read_UINT32(s, context->capsFlags); /* dwFlags */
198  Stream_Read_UINT32(s, context->initialVolume); /* dwVolume */
199  Stream_Read_UINT32(s, context->initialPitch); /* dwPitch */
200  Stream_Read_UINT16(s, udpPort); /* wDGramPort */
201  Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */
202  Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */
203  Stream_Read_UINT16(s, context->clientVersion); /* wVersion */
204  Stream_Seek_UINT8(s); /* bPad */
205 
206  /* this check is only a guess as cbSize can influence the size of a format record */
207  if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, context->num_client_formats, 18ull))
208  return ERROR_INVALID_DATA;
209 
210  if (!context->num_client_formats)
211  {
212  WLog_ERR(TAG, "client doesn't support any format!");
213  return ERROR_INTERNAL_ERROR;
214  }
215 
216  context->client_formats = audio_formats_new(context->num_client_formats);
217 
218  if (!context->client_formats)
219  {
220  WLog_ERR(TAG, "calloc failed!");
221  return CHANNEL_RC_NO_MEMORY;
222  }
223 
224  for (UINT16 i = 0; i < context->num_client_formats; i++)
225  {
226  AUDIO_FORMAT* format = &context->client_formats[i];
227 
228  if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
229  {
230  WLog_ERR(TAG, "not enough data in stream!");
231  error = ERROR_INVALID_DATA;
232  goto out_free;
233  }
234 
235  Stream_Read_UINT16(s, format->wFormatTag);
236  Stream_Read_UINT16(s, format->nChannels);
237  Stream_Read_UINT32(s, format->nSamplesPerSec);
238  Stream_Read_UINT32(s, format->nAvgBytesPerSec);
239  Stream_Read_UINT16(s, format->nBlockAlign);
240  Stream_Read_UINT16(s, format->wBitsPerSample);
241  Stream_Read_UINT16(s, format->cbSize);
242 
243  if (format->cbSize > 0)
244  {
245  if (!Stream_SafeSeek(s, format->cbSize))
246  {
247  WLog_ERR(TAG, "Stream_SafeSeek failed!");
248  error = ERROR_INTERNAL_ERROR;
249  goto out_free;
250  }
251  }
252 
253  if (format->wFormatTag != 0)
254  {
255  // lets call this a known format
256  // TODO: actually look through our own list of known formats
257  num_known_format++;
258  }
259  }
260 
261  if (!context->num_client_formats)
262  {
263  WLog_ERR(TAG, "client doesn't support any known format!");
264  goto out_free;
265  }
266 
267  return CHANNEL_RC_OK;
268 out_free:
269  free(context->client_formats);
270  return error;
271 }
272 
273 static DWORD WINAPI rdpsnd_server_thread(LPVOID arg)
274 {
275  DWORD nCount = 0;
276  DWORD status = 0;
277  HANDLE events[2] = { 0 };
278  RdpsndServerContext* context = (RdpsndServerContext*)arg;
279  UINT error = CHANNEL_RC_OK;
280 
281  WINPR_ASSERT(context);
282  WINPR_ASSERT(context->priv);
283 
284  events[nCount++] = context->priv->channelEvent;
285  events[nCount++] = context->priv->StopEvent;
286 
287  WINPR_ASSERT(nCount <= ARRAYSIZE(events));
288 
289  while (TRUE)
290  {
291  status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
292 
293  if (status == WAIT_FAILED)
294  {
295  error = GetLastError();
296  WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
297  break;
298  }
299 
300  status = WaitForSingleObject(context->priv->StopEvent, 0);
301 
302  if (status == WAIT_FAILED)
303  {
304  error = GetLastError();
305  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
306  break;
307  }
308 
309  if (status == WAIT_OBJECT_0)
310  break;
311 
312  if ((error = rdpsnd_server_handle_messages(context)))
313  {
314  WLog_ERR(TAG, "rdpsnd_server_handle_messages failed with error %" PRIu32 "", error);
315  break;
316  }
317  }
318 
319  if (error && context->rdpcontext)
320  setChannelError(context->rdpcontext, error, "rdpsnd_server_thread reported an error");
321 
322  ExitThread(error);
323  return error;
324 }
325 
331 static UINT rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread)
332 {
333  WINPR_ASSERT(context);
334  WINPR_ASSERT(context->priv);
335 
336  context->priv->ownThread = ownThread;
337  return context->Start(context);
338 }
339 
345 static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 client_format_index)
346 {
347  size_t bs = 0;
348  size_t out_buffer_size = 0;
349  AUDIO_FORMAT* format = NULL;
350  UINT error = CHANNEL_RC_OK;
351 
352  WINPR_ASSERT(context);
353  WINPR_ASSERT(context->priv);
354 
355  if ((client_format_index >= context->num_client_formats) || (!context->src_format))
356  {
357  WLog_ERR(TAG, "index %" PRIu16 " is not correct.", client_format_index);
358  return ERROR_INVALID_DATA;
359  }
360 
361  EnterCriticalSection(&context->priv->lock);
362  context->priv->src_bytes_per_sample = context->src_format->wBitsPerSample / 8;
363  context->priv->src_bytes_per_frame =
364  context->priv->src_bytes_per_sample * context->src_format->nChannels;
365  context->selected_client_format = client_format_index;
366  format = &context->client_formats[client_format_index];
367 
368  if (format->nSamplesPerSec == 0)
369  {
370  WLog_ERR(TAG, "invalid Client Sound Format!!");
371  error = ERROR_INVALID_DATA;
372  goto out;
373  }
374 
375  if (context->latency <= 0)
376  context->latency = 50;
377 
378  context->priv->out_frames = context->src_format->nSamplesPerSec * context->latency / 1000;
379 
380  if (context->priv->out_frames < 1)
381  context->priv->out_frames = 1;
382 
383  switch (format->wFormatTag)
384  {
385  case WAVE_FORMAT_DVI_ADPCM:
386  bs = 4ULL * (format->nBlockAlign - 4ULL * format->nChannels);
387  context->priv->out_frames -= context->priv->out_frames % bs;
388 
389  if (context->priv->out_frames < bs)
390  context->priv->out_frames = bs;
391 
392  break;
393 
394  case WAVE_FORMAT_ADPCM:
395  bs = (format->nBlockAlign - 7 * format->nChannels) * 2 / format->nChannels + 2;
396  context->priv->out_frames -= context->priv->out_frames % bs;
397 
398  if (context->priv->out_frames < bs)
399  context->priv->out_frames = bs;
400 
401  break;
402  default:
403  break;
404  }
405 
406  context->priv->out_pending_frames = 0;
407  out_buffer_size = context->priv->out_frames * context->priv->src_bytes_per_frame;
408 
409  if (context->priv->out_buffer_size < out_buffer_size)
410  {
411  BYTE* newBuffer = NULL;
412  newBuffer = (BYTE*)realloc(context->priv->out_buffer, out_buffer_size);
413 
414  if (!newBuffer)
415  {
416  WLog_ERR(TAG, "realloc failed!");
417  error = CHANNEL_RC_NO_MEMORY;
418  goto out;
419  }
420 
421  context->priv->out_buffer = newBuffer;
422  context->priv->out_buffer_size = out_buffer_size;
423  }
424 
425  freerdp_dsp_context_reset(context->priv->dsp_context, format, 0u);
426 out:
427  LeaveCriticalSection(&context->priv->lock);
428  return error;
429 }
430 
436 static UINT rdpsnd_server_training(RdpsndServerContext* context, UINT16 timestamp, UINT16 packsize,
437  BYTE* data)
438 {
439  ULONG written = 0;
440  BOOL status = 0;
441  wStream* s = rdpsnd_server_get_buffer(context);
442 
443  if (!Stream_EnsureRemainingCapacity(s, 8))
444  return ERROR_INTERNAL_ERROR;
445 
446  Stream_Write_UINT8(s, SNDC_TRAINING);
447  Stream_Write_UINT8(s, 0);
448  Stream_Seek_UINT16(s);
449  Stream_Write_UINT16(s, timestamp);
450  Stream_Write_UINT16(s, packsize);
451 
452  if (packsize > 0)
453  {
454  if (!Stream_EnsureRemainingCapacity(s, packsize))
455  {
456  Stream_SetPosition(s, 0);
457  return ERROR_INTERNAL_ERROR;
458  }
459 
460  Stream_Write(s, data, packsize);
461  }
462 
463  const size_t end = Stream_GetPosition(s);
464  if ((end < 4) || (end > UINT16_MAX))
465  return ERROR_INTERNAL_ERROR;
466 
467  Stream_SetPosition(s, 2);
468  Stream_Write_UINT16(s, (UINT16)(end - 4));
469 
470  status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
471  (UINT32)end, &written);
472 
473  Stream_SetPosition(s, 0);
474 
475  return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
476 }
477 
478 static BOOL rdpsnd_server_align_wave_pdu(wStream* s, UINT32 alignment)
479 {
480  size_t size = 0;
481  Stream_SealLength(s);
482  size = Stream_Length(s);
483 
484  if ((size % alignment) != 0)
485  {
486  size_t offset = alignment - size % alignment;
487 
488  if (!Stream_EnsureRemainingCapacity(s, offset))
489  return FALSE;
490 
491  Stream_Zero(s, offset);
492  }
493 
494  Stream_SealLength(s);
495  return TRUE;
496 }
497 
504 static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
505 {
506  AUDIO_FORMAT* format = NULL;
507  ULONG written = 0;
508  UINT error = CHANNEL_RC_OK;
509  wStream* s = rdpsnd_server_get_buffer(context);
510 
511  if (context->selected_client_format > context->num_client_formats)
512  return ERROR_INTERNAL_ERROR;
513 
514  WINPR_ASSERT(context->client_formats);
515 
516  format = &context->client_formats[context->selected_client_format];
517  /* WaveInfo PDU */
518  Stream_SetPosition(s, 0);
519 
520  if (!Stream_EnsureRemainingCapacity(s, 16))
521  return ERROR_OUTOFMEMORY;
522 
523  Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */
524  Stream_Write_UINT8(s, 0); /* bPad */
525  Stream_Write_UINT16(s, 0); /* BodySize */
526  Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */
527  Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */
528  Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
529  Stream_Seek(s, 3); /* bPad */
530  const size_t start = Stream_GetPosition(s);
531  const BYTE* src = context->priv->out_buffer;
532  const size_t length =
533  1ull * context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
534 
535  if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s))
536  return ERROR_INTERNAL_ERROR;
537 
538  /* Set stream size */
539  if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
540  return ERROR_INTERNAL_ERROR;
541 
542  const size_t end = Stream_GetPosition(s);
543  const size_t pos = end - start + 8ULL;
544  if (pos > UINT16_MAX)
545  return ERROR_INTERNAL_ERROR;
546  Stream_SetPosition(s, 2);
547  Stream_Write_UINT16(s, (UINT16)pos);
548  Stream_SetPosition(s, end);
549 
550  if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
551  (UINT32)(start + 4), &written))
552  {
553  WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
554  error = ERROR_INTERNAL_ERROR;
555  }
556 
557  if (error != CHANNEL_RC_OK)
558  {
559  WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
560  error = ERROR_INTERNAL_ERROR;
561  goto out;
562  }
563 
564  Stream_SetPosition(s, start);
565  Stream_Write_UINT32(s, 0); /* bPad */
566  Stream_SetPosition(s, start);
567 
568  WINPR_ASSERT((end - start) <= UINT32_MAX);
569  if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_Pointer(s),
570  (UINT32)(end - start), &written))
571  {
572  WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
573  error = ERROR_INTERNAL_ERROR;
574  }
575 
576  context->block_no = (context->block_no + 1) % 256;
577 
578 out:
579  Stream_SetPosition(s, 0);
580  context->priv->out_pending_frames = 0;
581  return error;
582 }
583 
590 static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 formatNo,
591  const BYTE* data, size_t size, BOOL encoded,
592  UINT16 timestamp, UINT32 audioTimeStamp)
593 {
594  ULONG written = 0;
595  UINT error = CHANNEL_RC_OK;
596  BOOL status = 0;
597  wStream* s = rdpsnd_server_get_buffer(context);
598 
599  if (!Stream_EnsureRemainingCapacity(s, 16))
600  {
601  error = ERROR_INTERNAL_ERROR;
602  goto out;
603  }
604 
605  /* Wave2 PDU */
606  Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */
607  Stream_Write_UINT8(s, 0); /* bPad */
608  Stream_Write_UINT16(s, 0); /* BodySize */
609  Stream_Write_UINT16(s, timestamp); /* wTimeStamp */
610  Stream_Write_UINT16(s, formatNo); /* wFormatNo */
611  Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
612  Stream_Write_UINT8(s, 0); /* bPad */
613  Stream_Write_UINT8(s, 0); /* bPad */
614  Stream_Write_UINT8(s, 0); /* bPad */
615  Stream_Write_UINT32(s, audioTimeStamp); /* dwAudioTimeStamp */
616 
617  if (encoded)
618  {
619  if (!Stream_EnsureRemainingCapacity(s, size))
620  {
621  error = ERROR_INTERNAL_ERROR;
622  goto out;
623  }
624 
625  Stream_Write(s, data, size);
626  }
627  else
628  {
629  AUDIO_FORMAT* format = NULL;
630 
631  if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, data, size, s))
632  {
633  error = ERROR_INTERNAL_ERROR;
634  goto out;
635  }
636 
637  format = &context->client_formats[formatNo];
638  if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign))
639  {
640  error = ERROR_INTERNAL_ERROR;
641  goto out;
642  }
643  }
644 
645  const size_t end = Stream_GetPosition(s);
646  if (end > UINT16_MAX + 4)
647  {
648  error = ERROR_INTERNAL_ERROR;
649  goto out;
650  }
651 
652  Stream_SetPosition(s, 2);
653  Stream_Write_UINT16(s, (UINT16)(end - 4));
654 
655  status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
656  (UINT32)end, &written);
657 
658  if (!status || (end != written))
659  {
660  WLog_ERR(TAG, "WTSVirtualChannelWrite failed! [stream length=%" PRIuz " - written=%" PRIu32,
661  end, written);
662  error = ERROR_INTERNAL_ERROR;
663  }
664 
665  context->block_no = (context->block_no + 1) % 256;
666 
667 out:
668  Stream_SetPosition(s, 0);
669  context->priv->out_pending_frames = 0;
670  return error;
671 }
672 
673 /* Wrapper function to send WAVE or WAVE2 PDU depending on client connected */
674 static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
675 {
676  const BYTE* src = NULL;
677  size_t length = 0;
678 
679  WINPR_ASSERT(context);
680  WINPR_ASSERT(context->priv);
681 
682  if (context->selected_client_format >= context->num_client_formats)
683  return ERROR_INTERNAL_ERROR;
684 
685  src = context->priv->out_buffer;
686  length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame;
687 
688  if (context->clientVersion >= CHANNEL_VERSION_WIN_8)
689  return rdpsnd_server_send_wave2_pdu(context, context->selected_client_format, src, length,
690  FALSE, wTimestamp, wTimestamp);
691  else
692  return rdpsnd_server_send_wave_pdu(context, wTimestamp);
693 }
694 
700 static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf,
701  size_t nframes, UINT16 wTimestamp)
702 {
703  UINT error = CHANNEL_RC_OK;
704 
705  WINPR_ASSERT(context);
706  WINPR_ASSERT(context->priv);
707 
708  EnterCriticalSection(&context->priv->lock);
709 
710  if (context->selected_client_format >= context->num_client_formats)
711  {
712  /* It's possible while format negotiation has not been done */
713  WLog_WARN(TAG, "Drop samples because client format has not been negotiated.");
714  error = ERROR_NOT_READY;
715  goto out;
716  }
717 
718  while (nframes > 0)
719  {
720  const size_t cframes =
721  MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames);
722  size_t cframesize = cframes * context->priv->src_bytes_per_frame;
723  CopyMemory(context->priv->out_buffer +
724  (context->priv->out_pending_frames * context->priv->src_bytes_per_frame),
725  buf, cframesize);
726  buf = (const BYTE*)buf + cframesize;
727  nframes -= cframes;
728  context->priv->out_pending_frames += cframes;
729 
730  if (context->priv->out_pending_frames >= context->priv->out_frames)
731  {
732  if ((error = rdpsnd_server_send_audio_pdu(context, wTimestamp)))
733  {
734  WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error);
735  break;
736  }
737  }
738  }
739 
740 out:
741  LeaveCriticalSection(&context->priv->lock);
742  return error;
743 }
744 
750 static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 formatNo,
751  const void* buf, size_t size, UINT16 timestamp,
752  UINT32 audioTimeStamp)
753 {
754  UINT error = CHANNEL_RC_OK;
755 
756  WINPR_ASSERT(context);
757  WINPR_ASSERT(context->priv);
758 
759  if (context->clientVersion < CHANNEL_VERSION_WIN_8)
760  return ERROR_INTERNAL_ERROR;
761 
762  EnterCriticalSection(&context->priv->lock);
763 
764  error =
765  rdpsnd_server_send_wave2_pdu(context, formatNo, buf, size, TRUE, timestamp, audioTimeStamp);
766 
767  LeaveCriticalSection(&context->priv->lock);
768 
769  return error;
770 }
771 
777 static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, UINT16 left, UINT16 right)
778 {
779  BOOL status = 0;
780  ULONG written = 0;
781  wStream* s = rdpsnd_server_get_buffer(context);
782 
783  if (!Stream_EnsureRemainingCapacity(s, 8))
784  return ERROR_NOT_ENOUGH_MEMORY;
785 
786  Stream_Write_UINT8(s, SNDC_SETVOLUME);
787  Stream_Write_UINT8(s, 0);
788  Stream_Write_UINT16(s, 4); /* Payload length */
789  Stream_Write_UINT16(s, left);
790  Stream_Write_UINT16(s, right);
791 
792  const size_t len = Stream_GetPosition(s);
793  WINPR_ASSERT(len <= UINT32_MAX);
794  status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
795  (ULONG)len, &written);
796  Stream_SetPosition(s, 0);
797  return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
798 }
799 
805 static UINT rdpsnd_server_close(RdpsndServerContext* context)
806 {
807  BOOL status = 0;
808  ULONG written = 0;
809  UINT error = CHANNEL_RC_OK;
810  wStream* s = rdpsnd_server_get_buffer(context);
811 
812  EnterCriticalSection(&context->priv->lock);
813 
814  if (context->priv->out_pending_frames > 0)
815  {
816  if (context->selected_client_format >= context->num_client_formats)
817  {
818  WLog_ERR(TAG, "Pending audio frame exists while no format selected.");
819  error = ERROR_INVALID_DATA;
820  }
821  else if ((error = rdpsnd_server_send_audio_pdu(context, 0)))
822  {
823  WLog_ERR(TAG, "rdpsnd_server_send_audio_pdu failed with error %" PRIu32 "", error);
824  }
825  }
826 
827  LeaveCriticalSection(&context->priv->lock);
828 
829  if (error)
830  return error;
831 
832  context->selected_client_format = 0xFFFF;
833 
834  if (!Stream_EnsureRemainingCapacity(s, 4))
835  return ERROR_OUTOFMEMORY;
836 
837  Stream_Write_UINT8(s, SNDC_CLOSE);
838  Stream_Write_UINT8(s, 0);
839  Stream_Seek_UINT16(s);
840  const size_t pos = Stream_GetPosition(s);
841  WINPR_ASSERT(pos >= 4);
842  Stream_SetPosition(s, 2);
843  Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, pos - 4));
844  Stream_SetPosition(s, pos);
845 
846  const size_t len = Stream_GetPosition(s);
847  WINPR_ASSERT(len <= UINT32_MAX);
848  status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char),
849  (UINT32)len, &written);
850  Stream_SetPosition(s, 0);
851  return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
852 }
853 
859 static UINT rdpsnd_server_start(RdpsndServerContext* context)
860 {
861  void* buffer = NULL;
862  DWORD bytesReturned = 0;
863  RdpsndServerPrivate* priv = NULL;
864  UINT error = ERROR_INTERNAL_ERROR;
865  PULONG pSessionId = NULL;
866 
867  WINPR_ASSERT(context);
868  WINPR_ASSERT(context->priv);
869 
870  priv = context->priv;
871  priv->SessionId = WTS_CURRENT_SESSION;
872 
873  if (context->use_dynamic_virtual_channel)
874  {
875  UINT32 channelId = 0;
876  BOOL status = TRUE;
877 
878  if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
879  (LPSTR*)&pSessionId, &bytesReturned))
880  {
881  priv->SessionId = (DWORD)*pSessionId;
882  WTSFreeMemory(pSessionId);
883  priv->ChannelHandle = WTSVirtualChannelOpenEx(priv->SessionId, RDPSND_DVC_CHANNEL_NAME,
884  WTS_CHANNEL_OPTION_DYNAMIC);
885  if (!priv->ChannelHandle)
886  {
887  WLog_ERR(TAG, "Open audio dynamic virtual channel (%s) failed!",
888  RDPSND_DVC_CHANNEL_NAME);
889  return ERROR_INTERNAL_ERROR;
890  }
891 
892  channelId = WTSChannelGetIdByHandle(priv->ChannelHandle);
893 
894  IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
895  if (!status)
896  {
897  WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
898  goto out_close;
899  }
900  }
901  else
902  {
903  WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
904  return ERROR_INTERNAL_ERROR;
905  }
906  }
907  else
908  {
909  priv->ChannelHandle =
910  WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPSND_CHANNEL_NAME);
911  if (!priv->ChannelHandle)
912  {
913  WLog_ERR(TAG, "Open audio static virtual channel (rdpsnd) failed!");
914  return ERROR_INTERNAL_ERROR;
915  }
916  }
917 
918  if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer,
919  &bytesReturned) ||
920  (bytesReturned != sizeof(HANDLE)))
921  {
922  WLog_ERR(TAG,
923  "error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned "
924  "size(%" PRIu32 ")",
925  bytesReturned);
926 
927  if (buffer)
928  WTSFreeMemory(buffer);
929 
930  goto out_close;
931  }
932 
933  priv->channelEvent = *(HANDLE*)buffer;
934  WTSFreeMemory(buffer);
935  priv->rdpsnd_pdu = Stream_New(NULL, 4096);
936 
937  if (!priv->rdpsnd_pdu)
938  {
939  WLog_ERR(TAG, "Stream_New failed!");
940  error = CHANNEL_RC_NO_MEMORY;
941  goto out_close;
942  }
943 
944  if (!InitializeCriticalSectionEx(&context->priv->lock, 0, 0))
945  {
946  WLog_ERR(TAG, "InitializeCriticalSectionEx failed!");
947  goto out_pdu;
948  }
949 
950  if ((error = rdpsnd_server_send_formats(context)))
951  {
952  WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %" PRIu32 "", error);
953  goto out_lock;
954  }
955 
956  if (priv->ownThread)
957  {
958  context->priv->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
959 
960  if (!context->priv->StopEvent)
961  {
962  WLog_ERR(TAG, "CreateEvent failed!");
963  goto out_lock;
964  }
965 
966  context->priv->Thread =
967  CreateThread(NULL, 0, rdpsnd_server_thread, (void*)context, 0, NULL);
968 
969  if (!context->priv->Thread)
970  {
971  WLog_ERR(TAG, "CreateThread failed!");
972  goto out_stopEvent;
973  }
974  }
975 
976  return CHANNEL_RC_OK;
977 out_stopEvent:
978  (void)CloseHandle(context->priv->StopEvent);
979  context->priv->StopEvent = NULL;
980 out_lock:
981  DeleteCriticalSection(&context->priv->lock);
982 out_pdu:
983  Stream_Free(context->priv->rdpsnd_pdu, TRUE);
984  context->priv->rdpsnd_pdu = NULL;
985 out_close:
986  (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
987  context->priv->ChannelHandle = NULL;
988  return error;
989 }
990 
996 static UINT rdpsnd_server_stop(RdpsndServerContext* context)
997 {
998  UINT error = CHANNEL_RC_OK;
999 
1000  WINPR_ASSERT(context);
1001  WINPR_ASSERT(context->priv);
1002 
1003  if (!context->priv->StopEvent)
1004  return error;
1005 
1006  if (context->priv->ownThread)
1007  {
1008  if (context->priv->StopEvent)
1009  {
1010  (void)SetEvent(context->priv->StopEvent);
1011 
1012  if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED)
1013  {
1014  error = GetLastError();
1015  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
1016  return error;
1017  }
1018 
1019  (void)CloseHandle(context->priv->Thread);
1020  (void)CloseHandle(context->priv->StopEvent);
1021  context->priv->Thread = NULL;
1022  context->priv->StopEvent = NULL;
1023  }
1024  }
1025 
1026  DeleteCriticalSection(&context->priv->lock);
1027 
1028  if (context->priv->rdpsnd_pdu)
1029  {
1030  Stream_Free(context->priv->rdpsnd_pdu, TRUE);
1031  context->priv->rdpsnd_pdu = NULL;
1032  }
1033 
1034  if (context->priv->ChannelHandle)
1035  {
1036  (void)WTSVirtualChannelClose(context->priv->ChannelHandle);
1037  context->priv->ChannelHandle = NULL;
1038  }
1039 
1040  return error;
1041 }
1042 
1043 RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm)
1044 {
1045  RdpsndServerPrivate* priv = NULL;
1046  RdpsndServerContext* context = (RdpsndServerContext*)calloc(1, sizeof(RdpsndServerContext));
1047 
1048  if (!context)
1049  goto fail;
1050 
1051  context->vcm = vcm;
1052  context->Start = rdpsnd_server_start;
1053  context->Stop = rdpsnd_server_stop;
1054  context->selected_client_format = 0xFFFF;
1055  context->Initialize = rdpsnd_server_initialize;
1056  context->SendFormats = rdpsnd_server_send_formats;
1057  context->SelectFormat = rdpsnd_server_select_format;
1058  context->Training = rdpsnd_server_training;
1059  context->SendSamples = rdpsnd_server_send_samples;
1060  context->SendSamples2 = rdpsnd_server_send_samples2;
1061  context->SetVolume = rdpsnd_server_set_volume;
1062  context->Close = rdpsnd_server_close;
1063  context->priv = priv = (RdpsndServerPrivate*)calloc(1, sizeof(RdpsndServerPrivate));
1064 
1065  if (!priv)
1066  {
1067  WLog_ERR(TAG, "calloc failed!");
1068  goto fail;
1069  }
1070 
1071  priv->dsp_context = freerdp_dsp_context_new(TRUE);
1072 
1073  if (!priv->dsp_context)
1074  {
1075  WLog_ERR(TAG, "freerdp_dsp_context_new failed!");
1076  goto fail;
1077  }
1078 
1079  priv->input_stream = Stream_New(NULL, 4);
1080 
1081  if (!priv->input_stream)
1082  {
1083  WLog_ERR(TAG, "Stream_New failed!");
1084  goto fail;
1085  }
1086 
1087  priv->expectedBytes = 4;
1088  priv->waitingHeader = TRUE;
1089  priv->ownThread = TRUE;
1090  return context;
1091 fail:
1092  WINPR_PRAGMA_DIAG_PUSH
1093  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1094  rdpsnd_server_context_free(context);
1095  WINPR_PRAGMA_DIAG_POP
1096  return NULL;
1097 }
1098 
1099 void rdpsnd_server_context_reset(RdpsndServerContext* context)
1100 {
1101  WINPR_ASSERT(context);
1102  WINPR_ASSERT(context->priv);
1103 
1104  context->priv->expectedBytes = 4;
1105  context->priv->waitingHeader = TRUE;
1106  Stream_SetPosition(context->priv->input_stream, 0);
1107 }
1108 
1109 void rdpsnd_server_context_free(RdpsndServerContext* context)
1110 {
1111  if (!context)
1112  return;
1113 
1114  if (context->priv)
1115  {
1116  rdpsnd_server_stop(context);
1117 
1118  free(context->priv->out_buffer);
1119 
1120  if (context->priv->dsp_context)
1121  freerdp_dsp_context_free(context->priv->dsp_context);
1122 
1123  if (context->priv->input_stream)
1124  Stream_Free(context->priv->input_stream, TRUE);
1125  }
1126 
1127  free(context->server_formats);
1128  free(context->client_formats);
1129  free(context->priv);
1130  free(context);
1131 }
1132 
1133 HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context)
1134 {
1135  WINPR_ASSERT(context);
1136  WINPR_ASSERT(context->priv);
1137 
1138  return context->priv->channelEvent;
1139 }
1140 
1141 /*
1142  * Handle rpdsnd messages - server side
1143  *
1144  * @param Server side context
1145  *
1146  * @return 0 on success
1147  * ERROR_NO_DATA if no data could be read this time
1148  * otherwise error
1149  */
1155 UINT rdpsnd_server_handle_messages(RdpsndServerContext* context)
1156 {
1157  DWORD bytesReturned = 0;
1158  UINT ret = CHANNEL_RC_OK;
1159  RdpsndServerPrivate* priv = NULL;
1160  wStream* s = NULL;
1161 
1162  WINPR_ASSERT(context);
1163  WINPR_ASSERT(context->priv);
1164 
1165  priv = context->priv;
1166  s = priv->input_stream;
1167 
1168  if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, Stream_Pointer(s), priv->expectedBytes,
1169  &bytesReturned))
1170  {
1171  if (GetLastError() == ERROR_NO_DATA)
1172  return ERROR_NO_DATA;
1173 
1174  WLog_ERR(TAG, "channel connection closed");
1175  return ERROR_INTERNAL_ERROR;
1176  }
1177 
1178  priv->expectedBytes -= bytesReturned;
1179  Stream_Seek(s, bytesReturned);
1180 
1181  if (priv->expectedBytes)
1182  return CHANNEL_RC_OK;
1183 
1184  Stream_SealLength(s);
1185  Stream_SetPosition(s, 0);
1186 
1187  if (priv->waitingHeader)
1188  {
1189  /* header case */
1190  Stream_Read_UINT8(s, priv->msgType);
1191  Stream_Seek_UINT8(s); /* bPad */
1192  Stream_Read_UINT16(s, priv->expectedBytes);
1193  priv->waitingHeader = FALSE;
1194  Stream_SetPosition(s, 0);
1195 
1196  if (priv->expectedBytes)
1197  {
1198  if (!Stream_EnsureCapacity(s, priv->expectedBytes))
1199  {
1200  WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
1201  return CHANNEL_RC_NO_MEMORY;
1202  }
1203 
1204  return CHANNEL_RC_OK;
1205  }
1206  }
1207 
1208  /* when here we have the header + the body */
1209 #ifdef WITH_DEBUG_SND
1210  WLog_DBG(TAG, "message type %" PRIu8 "", priv->msgType);
1211 #endif
1212  priv->expectedBytes = 4;
1213  priv->waitingHeader = TRUE;
1214 
1215  switch (priv->msgType)
1216  {
1217  case SNDC_WAVECONFIRM:
1218  ret = rdpsnd_server_recv_waveconfirm(context, s);
1219  break;
1220 
1221  case SNDC_TRAINING:
1222  ret = rdpsnd_server_recv_trainingconfirm(context, s);
1223  break;
1224 
1225  case SNDC_FORMATS:
1226  ret = rdpsnd_server_recv_formats(context, s);
1227 
1228  if ((ret == CHANNEL_RC_OK) && (context->clientVersion < CHANNEL_VERSION_WIN_7))
1229  IFCALL(context->Activated, context);
1230 
1231  break;
1232 
1233  case SNDC_QUALITYMODE:
1234  ret = rdpsnd_server_recv_quality_mode(context, s);
1235 
1236  if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7))
1237  IFCALL(context->Activated, context);
1238 
1239  break;
1240 
1241  default:
1242  WLog_ERR(TAG, "UNKNOWN MESSAGE TYPE!! (0x%02" PRIX8 ")", priv->msgType);
1243  ret = ERROR_INVALID_DATA;
1244  break;
1245  }
1246 
1247  Stream_SetPosition(s, 0);
1248  return ret;
1249 }