FreeRDP
tsmf_main.c
1 
22 #include <freerdp/config.h>
23 
24 #include <winpr/crt.h>
25 #include <winpr/stream.h>
26 #include <winpr/cmdline.h>
27 
28 #include <freerdp/client/tsmf.h>
29 
30 #include "tsmf_types.h"
31 #include "tsmf_constants.h"
32 #include "tsmf_ifman.h"
33 #include "tsmf_media.h"
34 
35 #include "tsmf_main.h"
36 
37 BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id)
38 {
39  ssize_t status = -1;
40  TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback;
41 
42  if (!callback)
43  {
44  DEBUG_TSMF("No callback reference - unable to send eos response!");
45  return FALSE;
46  }
47 
48  if (callback && callback->stream_id && callback->channel && callback->channel->Write)
49  {
50  wStream* s = Stream_New(NULL, 24);
51 
52  if (!s)
53  return FALSE;
54 
55  Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY);
56  Stream_Write_UINT32(s, message_id);
57  Stream_Write_UINT32(s, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
58  Stream_Write_UINT32(s, callback->stream_id); /* StreamId */
59  Stream_Write_UINT32(s, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */
60  Stream_Write_UINT32(s, 0); /* cbData */
61  const size_t pos = Stream_GetPosition(s);
62  DEBUG_TSMF("EOS response size %" PRIuz "", pos);
63  WINPR_ASSERT(pos <= UINT32_MAX);
64  status = callback->channel->Write(callback->channel, (UINT32)pos, Stream_Buffer(s), NULL);
65 
66  if (status)
67  {
68  WLog_ERR(TAG, "response error %d", status);
69  }
70 
71  Stream_Free(s, TRUE);
72  }
73 
74  return (status == 0);
75 }
76 
77 BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id,
78  UINT64 duration, UINT32 data_size)
79 {
80  ssize_t status = -1;
81  TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback;
82 
83  if (!callback)
84  return FALSE;
85 
86  wStream* s = Stream_New(NULL, 32);
87 
88  if (!s)
89  return FALSE;
90 
91  Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY);
92  Stream_Write_UINT32(s, message_id);
93  Stream_Write_UINT32(s, PLAYBACK_ACK); /* FunctionId */
94  Stream_Write_UINT32(s, callback->stream_id); /* StreamId */
95  Stream_Write_UINT64(s, duration); /* DataDuration */
96  Stream_Write_UINT64(s, data_size); /* cbData */
97 
98  const size_t pos = Stream_GetPosition(s);
99  DEBUG_TSMF("ACK response size %" PRIuz "", pos);
100 
101  if (!callback->channel || !callback->channel->Write)
102  {
103  WLog_ERR(TAG, "callback=%p, channel=%p, write=%p", callback,
104  (callback ? callback->channel : NULL),
105  (callback && callback->channel ? callback->channel->Write : NULL));
106  }
107  else
108  {
109  WINPR_ASSERT(pos <= UINT32_MAX);
110  status = callback->channel->Write(callback->channel, (UINT32)pos, Stream_Buffer(s), NULL);
111  }
112 
113  if (status)
114  {
115  WLog_ERR(TAG, "response error %d", status);
116  }
117 
118  Stream_Free(s, TRUE);
119  return (status == 0);
120 }
121 
127 static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
128 {
129  wStream* input = NULL;
130  wStream* output = NULL;
131  UINT error = CHANNEL_RC_OK;
132  BOOL processed = FALSE;
133  TSMF_IFMAN ifman = { 0 };
134  UINT32 MessageId = 0;
135  UINT32 FunctionId = 0;
136  UINT32 InterfaceId = 0;
137  TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback;
138  const size_t cbSize = Stream_GetRemainingLength(data);
139 
140  /* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */
141  if (!Stream_CheckAndLogRequiredLength(TAG, data, 12) || (cbSize > UINT32_MAX))
142  return ERROR_INVALID_DATA;
143 
144  input = data;
145  output = Stream_New(NULL, 256);
146 
147  if (!output)
148  return ERROR_OUTOFMEMORY;
149 
150  Stream_Seek(output, 8);
151  Stream_Read_UINT32(input, InterfaceId); /* InterfaceId (4 bytes) */
152  Stream_Read_UINT32(input, MessageId); /* MessageId (4 bytes) */
153  Stream_Read_UINT32(input, FunctionId); /* FunctionId (4 bytes) */
154  DEBUG_TSMF("cbSize=%" PRIu32 " InterfaceId=0x%" PRIX32 " MessageId=0x%" PRIX32
155  " FunctionId=0x%" PRIX32 "",
156  cbSize, InterfaceId, MessageId, FunctionId);
157  ifman.channel_callback = pChannelCallback;
158  ifman.decoder_name = ((TSMF_PLUGIN*)callback->plugin)->decoder_name;
159  ifman.audio_name = ((TSMF_PLUGIN*)callback->plugin)->audio_name;
160  ifman.audio_device = ((TSMF_PLUGIN*)callback->plugin)->audio_device;
161  CopyMemory(ifman.presentation_id, callback->presentation_id, GUID_SIZE);
162  ifman.stream_id = callback->stream_id;
163  ifman.message_id = MessageId;
164  ifman.input = input;
165  ifman.input_size = (UINT32)(cbSize - 12U);
166  ifman.output = output;
167  ifman.output_pending = FALSE;
168  ifman.output_interface_id = InterfaceId;
169 
170  // (void)fprintf(stderr, "InterfaceId: 0x%08"PRIX32" MessageId: 0x%08"PRIX32" FunctionId:
171  // 0x%08"PRIX32"\n", InterfaceId, MessageId, FunctionId);
172 
173  switch (InterfaceId)
174  {
175  case TSMF_INTERFACE_CAPABILITIES | STREAM_ID_NONE:
176  switch (FunctionId)
177  {
178  case RIM_EXCHANGE_CAPABILITY_REQUEST:
179  error = tsmf_ifman_rim_exchange_capability_request(&ifman);
180  processed = TRUE;
181  break;
182 
183  case RIMCALL_RELEASE:
184  case RIMCALL_QUERYINTERFACE:
185  break;
186 
187  default:
188  break;
189  }
190 
191  break;
192 
193  case TSMF_INTERFACE_DEFAULT | STREAM_ID_PROXY:
194  switch (FunctionId)
195  {
196  case SET_CHANNEL_PARAMS:
197  if (!Stream_CheckAndLogRequiredLength(TAG, input, GUID_SIZE + 4))
198  {
199  error = ERROR_INVALID_DATA;
200  goto out;
201  }
202 
203  CopyMemory(callback->presentation_id, Stream_Pointer(input), GUID_SIZE);
204  Stream_Seek(input, GUID_SIZE);
205  Stream_Read_UINT32(input, callback->stream_id);
206  DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%" PRIu32 "", callback->stream_id);
207  ifman.output_pending = TRUE;
208  processed = TRUE;
209  break;
210 
211  case EXCHANGE_CAPABILITIES_REQ:
212  error = tsmf_ifman_exchange_capability_request(&ifman);
213  processed = TRUE;
214  break;
215 
216  case CHECK_FORMAT_SUPPORT_REQ:
217  error = tsmf_ifman_check_format_support_request(&ifman);
218  processed = TRUE;
219  break;
220 
221  case ON_NEW_PRESENTATION:
222  error = tsmf_ifman_on_new_presentation(&ifman);
223  processed = TRUE;
224  break;
225 
226  case ADD_STREAM:
227  error =
228  tsmf_ifman_add_stream(&ifman, ((TSMF_PLUGIN*)callback->plugin)->rdpcontext);
229  processed = TRUE;
230  break;
231 
232  case SET_TOPOLOGY_REQ:
233  error = tsmf_ifman_set_topology_request(&ifman);
234  processed = TRUE;
235  break;
236 
237  case REMOVE_STREAM:
238  error = tsmf_ifman_remove_stream(&ifman);
239  processed = TRUE;
240  break;
241 
242  case SET_SOURCE_VIDEO_RECT:
243  error = tsmf_ifman_set_source_video_rect(&ifman);
244  processed = TRUE;
245  break;
246 
247  case SHUTDOWN_PRESENTATION_REQ:
248  error = tsmf_ifman_shutdown_presentation(&ifman);
249  processed = TRUE;
250  break;
251 
252  case ON_STREAM_VOLUME:
253  error = tsmf_ifman_on_stream_volume(&ifman);
254  processed = TRUE;
255  break;
256 
257  case ON_CHANNEL_VOLUME:
258  error = tsmf_ifman_on_channel_volume(&ifman);
259  processed = TRUE;
260  break;
261 
262  case SET_VIDEO_WINDOW:
263  error = tsmf_ifman_set_video_window(&ifman);
264  processed = TRUE;
265  break;
266 
267  case UPDATE_GEOMETRY_INFO:
268  error = tsmf_ifman_update_geometry_info(&ifman);
269  processed = TRUE;
270  break;
271 
272  case SET_ALLOCATOR:
273  error = tsmf_ifman_set_allocator(&ifman);
274  processed = TRUE;
275  break;
276 
277  case NOTIFY_PREROLL:
278  error = tsmf_ifman_notify_preroll(&ifman);
279  processed = TRUE;
280  break;
281 
282  case ON_SAMPLE:
283  error = tsmf_ifman_on_sample(&ifman);
284  processed = TRUE;
285  break;
286 
287  case ON_FLUSH:
288  error = tsmf_ifman_on_flush(&ifman);
289  processed = TRUE;
290  break;
291 
292  case ON_END_OF_STREAM:
293  error = tsmf_ifman_on_end_of_stream(&ifman);
294  processed = TRUE;
295  break;
296 
297  case ON_PLAYBACK_STARTED:
298  error = tsmf_ifman_on_playback_started(&ifman);
299  processed = TRUE;
300  break;
301 
302  case ON_PLAYBACK_PAUSED:
303  error = tsmf_ifman_on_playback_paused(&ifman);
304  processed = TRUE;
305  break;
306 
307  case ON_PLAYBACK_RESTARTED:
308  error = tsmf_ifman_on_playback_restarted(&ifman);
309  processed = TRUE;
310  break;
311 
312  case ON_PLAYBACK_STOPPED:
313  error = tsmf_ifman_on_playback_stopped(&ifman);
314  processed = TRUE;
315  break;
316 
317  case ON_PLAYBACK_RATE_CHANGED:
318  error = tsmf_ifman_on_playback_rate_changed(&ifman);
319  processed = TRUE;
320  break;
321 
322  case RIMCALL_RELEASE:
323  case RIMCALL_QUERYINTERFACE:
324  break;
325 
326  default:
327  break;
328  }
329 
330  break;
331 
332  default:
333  break;
334  }
335 
336  input = NULL;
337  ifman.input = NULL;
338 
339  if (error)
340  {
341  WLog_ERR(TAG, "ifman data received processing error %" PRIu32 "", error);
342  }
343 
344  if (!processed)
345  {
346  switch (FunctionId)
347  {
348  case RIMCALL_RELEASE:
349  /* [MS-RDPEXPS] 2.2.2.2 Interface Release (IFACE_RELEASE)
350  This message does not require a reply. */
351  processed = TRUE;
352  ifman.output_pending = 1;
353  break;
354 
355  case RIMCALL_QUERYINTERFACE:
356  /* [MS-RDPEXPS] 2.2.2.1.2 Query Interface Response (QI_RSP)
357  This message is not supported in this channel. */
358  processed = TRUE;
359  break;
360  default:
361  break;
362  }
363 
364  if (!processed)
365  {
366  WLog_ERR(TAG,
367  "Unknown InterfaceId: 0x%08" PRIX32 " MessageId: 0x%08" PRIX32
368  " FunctionId: 0x%08" PRIX32 "\n",
369  InterfaceId, MessageId, FunctionId);
370  /* When a request is not implemented we return empty response indicating error */
371  }
372 
373  processed = TRUE;
374  }
375 
376  if (processed && !ifman.output_pending)
377  {
378  /* Response packet does not have FunctionId */
379  const size_t length = Stream_GetPosition(output);
380  if (length > UINT32_MAX)
381  goto out;
382  Stream_SetPosition(output, 0);
383  Stream_Write_UINT32(output, ifman.output_interface_id);
384  Stream_Write_UINT32(output, MessageId);
385  DEBUG_TSMF("response size %d", length);
386  error = callback->channel->Write(callback->channel, (UINT32)length, Stream_Buffer(output),
387  NULL);
388 
389  if (error)
390  {
391  WLog_ERR(TAG, "response error %" PRIu32 "", error);
392  }
393  }
394 
395 out:
396  Stream_Free(output, TRUE);
397  return error;
398 }
399 
405 static UINT tsmf_on_close(IWTSVirtualChannelCallback* pChannelCallback)
406 {
407  TSMF_STREAM* stream = NULL;
408  TSMF_PRESENTATION* presentation = NULL;
409  TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback;
410  DEBUG_TSMF("");
411 
412  if (callback->stream_id)
413  {
414  presentation = tsmf_presentation_find_by_id(callback->presentation_id);
415 
416  if (presentation)
417  {
418  stream = tsmf_stream_find_by_id(presentation, callback->stream_id);
419 
420  if (stream)
421  tsmf_stream_free(stream);
422  }
423  }
424 
425  free(pChannelCallback);
426  return CHANNEL_RC_OK;
427 }
428 
434 static UINT tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
435  IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
436  IWTSVirtualChannelCallback** ppCallback)
437 {
438  TSMF_CHANNEL_CALLBACK* callback = NULL;
439  TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*)pListenerCallback;
440  DEBUG_TSMF("");
441  callback = (TSMF_CHANNEL_CALLBACK*)calloc(1, sizeof(TSMF_CHANNEL_CALLBACK));
442 
443  if (!callback)
444  return CHANNEL_RC_NO_MEMORY;
445 
446  callback->iface.OnDataReceived = tsmf_on_data_received;
447  callback->iface.OnClose = tsmf_on_close;
448  callback->iface.OnOpen = NULL;
449  callback->plugin = listener_callback->plugin;
450  callback->channel_mgr = listener_callback->channel_mgr;
451  callback->channel = pChannel;
452  *ppCallback = (IWTSVirtualChannelCallback*)callback;
453  return CHANNEL_RC_OK;
454 }
455 
461 static UINT tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
462 {
463  UINT status = 0;
464  TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*)pPlugin;
465  DEBUG_TSMF("");
466  tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*)calloc(1, sizeof(TSMF_LISTENER_CALLBACK));
467 
468  if (!tsmf->listener_callback)
469  return CHANNEL_RC_NO_MEMORY;
470 
471  tsmf->listener_callback->iface.OnNewChannelConnection = tsmf_on_new_channel_connection;
472  tsmf->listener_callback->plugin = pPlugin;
473  tsmf->listener_callback->channel_mgr = pChannelMgr;
474  status = pChannelMgr->CreateListener(
475  pChannelMgr, "TSMF", 0, (IWTSListenerCallback*)tsmf->listener_callback, &(tsmf->listener));
476  tsmf->listener->pInterface = tsmf->iface.pInterface;
477  return status;
478 }
479 
485 static UINT tsmf_plugin_terminated(IWTSPlugin* pPlugin)
486 {
487  TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*)pPlugin;
488  DEBUG_TSMF("");
489  free(tsmf->listener_callback);
490  free(tsmf);
491  return CHANNEL_RC_OK;
492 }
493 
499 static UINT tsmf_process_addin_args(IWTSPlugin* pPlugin, const ADDIN_ARGV* args)
500 {
501  int status = 0;
502  DWORD flags = 0;
503  const COMMAND_LINE_ARGUMENT_A* arg = NULL;
504  TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*)pPlugin;
505  COMMAND_LINE_ARGUMENT_A tsmf_args[] = { { "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>",
506  NULL, NULL, -1, NULL, "audio subsystem" },
507  { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL,
508  NULL, -1, NULL, "audio device name" },
509  { "decoder", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>",
510  NULL, NULL, -1, NULL, "decoder subsystem" },
511  { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
512  flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
513  status = CommandLineParseArgumentsA(args->argc, args->argv, tsmf_args, flags, tsmf, NULL, NULL);
514 
515  if (status != 0)
516  return ERROR_INVALID_DATA;
517 
518  arg = tsmf_args;
519 
520  do
521  {
522  if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
523  continue;
524 
525  CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "sys")
526  {
527  tsmf->audio_name = _strdup(arg->Value);
528 
529  if (!tsmf->audio_name)
530  return ERROR_OUTOFMEMORY;
531  }
532  CommandLineSwitchCase(arg, "dev")
533  {
534  tsmf->audio_device = _strdup(arg->Value);
535 
536  if (!tsmf->audio_device)
537  return ERROR_OUTOFMEMORY;
538  }
539  CommandLineSwitchCase(arg, "decoder")
540  {
541  tsmf->decoder_name = _strdup(arg->Value);
542 
543  if (!tsmf->decoder_name)
544  return ERROR_OUTOFMEMORY;
545  }
546  CommandLineSwitchDefault(arg)
547  {
548  }
549  CommandLineSwitchEnd(arg)
550  } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
551 
552  return CHANNEL_RC_OK;
553 }
554 
560 FREERDP_ENTRY_POINT(UINT VCAPITYPE tsmf_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
561 {
562  UINT status = 0;
563  TSMF_PLUGIN* tsmf = NULL;
564  TsmfClientContext* context = NULL;
565  UINT error = CHANNEL_RC_NO_MEMORY;
566  tsmf = (TSMF_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "tsmf");
567 
568  if (!tsmf)
569  {
570  tsmf = (TSMF_PLUGIN*)calloc(1, sizeof(TSMF_PLUGIN));
571 
572  if (!tsmf)
573  {
574  WLog_ERR(TAG, "calloc failed!");
575  return CHANNEL_RC_NO_MEMORY;
576  }
577 
578  tsmf->iface.Initialize = tsmf_plugin_initialize;
579  tsmf->iface.Connected = NULL;
580  tsmf->iface.Disconnected = NULL;
581  tsmf->iface.Terminated = tsmf_plugin_terminated;
582  tsmf->rdpcontext = pEntryPoints->GetRdpContext(pEntryPoints);
583  context = (TsmfClientContext*)calloc(1, sizeof(TsmfClientContext));
584 
585  if (!context)
586  {
587  WLog_ERR(TAG, "calloc failed!");
588  goto error_context;
589  }
590 
591  context->handle = (void*)tsmf;
592  tsmf->iface.pInterface = (void*)context;
593 
594  if (!tsmf_media_init())
595  {
596  error = ERROR_INVALID_OPERATION;
597  goto error_init;
598  }
599 
600  status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", &tsmf->iface);
601  }
602 
603  if (status == CHANNEL_RC_OK)
604  {
605  status = tsmf_process_addin_args(&tsmf->iface, pEntryPoints->GetPluginData(pEntryPoints));
606  }
607 
608  return status;
609 error_init:
610  free(context);
611 error_context:
612  free(tsmf);
613  return error;
614 }