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