22 #include <freerdp/config.h>
24 #include <winpr/crt.h>
25 #include <winpr/stream.h>
26 #include <winpr/cmdline.h>
28 #include <freerdp/client/tsmf.h>
30 #include "tsmf_types.h"
31 #include "tsmf_constants.h"
32 #include "tsmf_ifman.h"
33 #include "tsmf_media.h"
35 #include "tsmf_main.h"
37 BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id)
44 DEBUG_TSMF(
"No callback reference - unable to send eos response!");
48 if (callback && callback->stream_id && callback->channel && callback->channel->Write)
50 wStream* s = Stream_New(NULL, 24);
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);
58 Stream_Write_UINT32(s, callback->stream_id);
59 Stream_Write_UINT32(s, TSMM_CLIENT_EVENT_ENDOFSTREAM);
60 Stream_Write_UINT32(s, 0);
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);
68 WLog_ERR(TAG,
"response error %d", status);
77 BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id,
78 UINT64 duration, UINT32 data_size)
86 wStream* s = Stream_New(NULL, 32);
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);
94 Stream_Write_UINT32(s, callback->stream_id);
95 Stream_Write_UINT64(s, duration);
96 Stream_Write_UINT64(s, data_size);
98 const size_t pos = Stream_GetPosition(s);
99 DEBUG_TSMF(
"ACK response size %" PRIuz
"", pos);
101 if (!callback->channel || !callback->channel->Write)
103 WLog_ERR(TAG,
"callback=%p, channel=%p, write=%p", callback,
104 (callback ? callback->channel : NULL),
105 (callback && callback->channel ? callback->channel->Write : NULL));
109 WINPR_ASSERT(pos <= UINT32_MAX);
110 status = callback->channel->Write(callback->channel, (UINT32)pos, Stream_Buffer(s), NULL);
115 WLog_ERR(TAG,
"response error %d", status);
118 Stream_Free(s, TRUE);
119 return (status == 0);
127 static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
131 UINT error = CHANNEL_RC_OK;
132 BOOL processed = FALSE;
134 UINT32 MessageId = 0;
135 UINT32 FunctionId = 0;
136 UINT32 InterfaceId = 0;
138 const size_t cbSize = Stream_GetRemainingLength(data);
141 if (!Stream_CheckAndLogRequiredLength(TAG, data, 12) || (cbSize > UINT32_MAX))
142 return ERROR_INVALID_DATA;
145 output = Stream_New(NULL, 256);
148 return ERROR_OUTOFMEMORY;
150 Stream_Seek(output, 8);
151 Stream_Read_UINT32(input, InterfaceId);
152 Stream_Read_UINT32(input, MessageId);
153 Stream_Read_UINT32(input, FunctionId);
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;
165 ifman.input_size = (UINT32)(cbSize - 12U);
166 ifman.output = output;
167 ifman.output_pending = FALSE;
168 ifman.output_interface_id = InterfaceId;
175 case TSMF_INTERFACE_CAPABILITIES | STREAM_ID_NONE:
178 case RIM_EXCHANGE_CAPABILITY_REQUEST:
179 error = tsmf_ifman_rim_exchange_capability_request(&ifman);
183 case RIMCALL_RELEASE:
184 case RIMCALL_QUERYINTERFACE:
193 case TSMF_INTERFACE_DEFAULT | STREAM_ID_PROXY:
196 case SET_CHANNEL_PARAMS:
197 if (!Stream_CheckAndLogRequiredLength(TAG, input, GUID_SIZE + 4))
199 error = ERROR_INVALID_DATA;
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;
211 case EXCHANGE_CAPABILITIES_REQ:
212 error = tsmf_ifman_exchange_capability_request(&ifman);
216 case CHECK_FORMAT_SUPPORT_REQ:
217 error = tsmf_ifman_check_format_support_request(&ifman);
221 case ON_NEW_PRESENTATION:
222 error = tsmf_ifman_on_new_presentation(&ifman);
228 tsmf_ifman_add_stream(&ifman, ((
TSMF_PLUGIN*)callback->plugin)->rdpcontext);
232 case SET_TOPOLOGY_REQ:
233 error = tsmf_ifman_set_topology_request(&ifman);
238 error = tsmf_ifman_remove_stream(&ifman);
242 case SET_SOURCE_VIDEO_RECT:
243 error = tsmf_ifman_set_source_video_rect(&ifman);
247 case SHUTDOWN_PRESENTATION_REQ:
248 error = tsmf_ifman_shutdown_presentation(&ifman);
252 case ON_STREAM_VOLUME:
253 error = tsmf_ifman_on_stream_volume(&ifman);
257 case ON_CHANNEL_VOLUME:
258 error = tsmf_ifman_on_channel_volume(&ifman);
262 case SET_VIDEO_WINDOW:
263 error = tsmf_ifman_set_video_window(&ifman);
267 case UPDATE_GEOMETRY_INFO:
268 error = tsmf_ifman_update_geometry_info(&ifman);
273 error = tsmf_ifman_set_allocator(&ifman);
278 error = tsmf_ifman_notify_preroll(&ifman);
283 error = tsmf_ifman_on_sample(&ifman);
288 error = tsmf_ifman_on_flush(&ifman);
292 case ON_END_OF_STREAM:
293 error = tsmf_ifman_on_end_of_stream(&ifman);
297 case ON_PLAYBACK_STARTED:
298 error = tsmf_ifman_on_playback_started(&ifman);
302 case ON_PLAYBACK_PAUSED:
303 error = tsmf_ifman_on_playback_paused(&ifman);
307 case ON_PLAYBACK_RESTARTED:
308 error = tsmf_ifman_on_playback_restarted(&ifman);
312 case ON_PLAYBACK_STOPPED:
313 error = tsmf_ifman_on_playback_stopped(&ifman);
317 case ON_PLAYBACK_RATE_CHANGED:
318 error = tsmf_ifman_on_playback_rate_changed(&ifman);
322 case RIMCALL_RELEASE:
323 case RIMCALL_QUERYINTERFACE:
341 WLog_ERR(TAG,
"ifman data received processing error %" PRIu32
"", error);
348 case RIMCALL_RELEASE:
352 ifman.output_pending = 1;
355 case RIMCALL_QUERYINTERFACE:
367 "Unknown InterfaceId: 0x%08" PRIX32
" MessageId: 0x%08" PRIX32
368 " FunctionId: 0x%08" PRIX32
"\n",
369 InterfaceId, MessageId, FunctionId);
376 if (processed && !ifman.output_pending)
379 const size_t length = Stream_GetPosition(output);
380 if (length > UINT32_MAX)
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),
391 WLog_ERR(TAG,
"response error %" PRIu32
"", error);
396 Stream_Free(output, TRUE);
405 static UINT tsmf_on_close(IWTSVirtualChannelCallback* pChannelCallback)
407 TSMF_STREAM* stream = NULL;
408 TSMF_PRESENTATION* presentation = NULL;
412 if (callback->stream_id)
414 presentation = tsmf_presentation_find_by_id(callback->presentation_id);
418 stream = tsmf_stream_find_by_id(presentation, callback->stream_id);
421 tsmf_stream_free(stream);
425 free(pChannelCallback);
426 return CHANNEL_RC_OK;
434 static UINT tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
435 IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
436 IWTSVirtualChannelCallback** ppCallback)
444 return CHANNEL_RC_NO_MEMORY;
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;
461 static UINT tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
468 if (!tsmf->listener_callback)
469 return CHANNEL_RC_NO_MEMORY;
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;
485 static UINT tsmf_plugin_terminated(IWTSPlugin* pPlugin)
489 free(tsmf->listener_callback);
491 return CHANNEL_RC_OK;
499 static UINT tsmf_process_addin_args(IWTSPlugin* pPlugin,
const ADDIN_ARGV* args)
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);
516 return ERROR_INVALID_DATA;
522 if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
525 CommandLineSwitchStart(arg) CommandLineSwitchCase(arg,
"sys")
527 tsmf->audio_name = _strdup(arg->Value);
529 if (!tsmf->audio_name)
530 return ERROR_OUTOFMEMORY;
532 CommandLineSwitchCase(arg,
"dev")
534 tsmf->audio_device = _strdup(arg->Value);
536 if (!tsmf->audio_device)
537 return ERROR_OUTOFMEMORY;
539 CommandLineSwitchCase(arg,
"decoder")
541 tsmf->decoder_name = _strdup(arg->Value);
543 if (!tsmf->decoder_name)
544 return ERROR_OUTOFMEMORY;
546 CommandLineSwitchDefault(arg)
549 CommandLineSwitchEnd(arg)
550 }
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
552 return CHANNEL_RC_OK;
560 FREERDP_ENTRY_POINT(UINT VCAPITYPE tsmf_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
564 TsmfClientContext* context = NULL;
565 UINT error = CHANNEL_RC_NO_MEMORY;
566 tsmf = (
TSMF_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints,
"tsmf");
574 WLog_ERR(TAG,
"calloc failed!");
575 return CHANNEL_RC_NO_MEMORY;
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));
587 WLog_ERR(TAG,
"calloc failed!");
591 context->handle = (
void*)tsmf;
592 tsmf->iface.pInterface = (
void*)context;
594 if (!tsmf_media_init())
596 error = ERROR_INVALID_OPERATION;
600 status = pEntryPoints->RegisterPlugin(pEntryPoints,
"tsmf", &tsmf->iface);
603 if (status == CHANNEL_RC_OK)
605 status = tsmf_process_addin_args(&tsmf->iface, pEntryPoints->GetPluginData(pEntryPoints));