FreeRDP
tsmf_ifman.c
1 
23 #include <freerdp/config.h>
24 
25 #include <math.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include <winpr/crt.h>
31 
32 #include <winpr/stream.h>
33 
34 #include "tsmf_types.h"
35 #include "tsmf_constants.h"
36 #include "tsmf_media.h"
37 #include "tsmf_codec.h"
38 
39 #include "tsmf_ifman.h"
40 
46 UINT tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
47 {
48  UINT32 CapabilityValue = 0;
49 
50  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 4))
51  return ERROR_INVALID_DATA;
52 
53  Stream_Read_UINT32(ifman->input, CapabilityValue);
54  DEBUG_TSMF("server CapabilityValue %" PRIu32 "", CapabilityValue);
55 
56  if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
57  return ERROR_INVALID_DATA;
58 
59  Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */
60  Stream_Write_UINT32(ifman->output, 0); /* Result */
61  return CHANNEL_RC_OK;
62 }
63 
69 UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
70 {
71  UINT32 CapabilityType = 0;
72  UINT32 cbCapabilityLength = 0;
73  UINT32 numHostCapabilities = 0;
74 
75  WINPR_ASSERT(ifman);
76  if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4))
77  return ERROR_OUTOFMEMORY;
78 
79  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, ifman->input_size))
80  return ERROR_INVALID_DATA;
81 
82  const size_t xpos = Stream_GetPosition(ifman->output);
83  Stream_Copy(ifman->input, ifman->output, ifman->input_size);
84  Stream_SetPosition(ifman->output, xpos);
85 
86  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, 4))
87  return ERROR_INVALID_DATA;
88 
89  Stream_Read_UINT32(ifman->output, numHostCapabilities);
90 
91  for (UINT32 i = 0; i < numHostCapabilities; i++)
92  {
93  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, 8))
94  return ERROR_INVALID_DATA;
95 
96  Stream_Read_UINT32(ifman->output, CapabilityType);
97  Stream_Read_UINT32(ifman->output, cbCapabilityLength);
98 
99  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, cbCapabilityLength))
100  return ERROR_INVALID_DATA;
101 
102  const size_t pos = Stream_GetPosition(ifman->output);
103 
104  switch (CapabilityType)
105  {
106  case 1: /* Protocol version request */
107  {
108  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, 4))
109  return ERROR_INVALID_DATA;
110 
111  const UINT32 v = Stream_Get_UINT32(ifman->output);
112  WINPR_UNUSED(v);
113  DEBUG_TSMF("server protocol version %" PRIu32 "", v);
114  }
115  break;
116 
117  case 2: /* Supported platform */
118  {
119  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, 4))
120  return ERROR_INVALID_DATA;
121 
122  const UINT32 v = Stream_Get_UINT32(ifman->output);
123  WINPR_UNUSED(v);
124  DEBUG_TSMF("server supported platform %" PRIu32 "", v);
125  /* Claim that we support both MF and DShow platforms. */
126  Stream_Write_UINT32(ifman->output, MMREDIR_CAPABILITY_PLATFORM_MF |
127  MMREDIR_CAPABILITY_PLATFORM_DSHOW);
128  }
129  break;
130 
131  default:
132  WLog_ERR(TAG, "skipping unknown capability type %" PRIu32 "", CapabilityType);
133  break;
134  }
135 
136  Stream_SetPosition(ifman->output, pos + cbCapabilityLength);
137  }
138 
139  Stream_Write_UINT32(ifman->output, 0); /* Result */
140  ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
141  return CHANNEL_RC_OK;
142 }
143 
149 UINT tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
150 {
151  UINT32 numMediaType = 0;
152  UINT32 PlatformCookie = 0;
153  UINT32 FormatSupported = 1;
154 
155  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 12))
156  return ERROR_INVALID_DATA;
157 
158  Stream_Read_UINT32(ifman->input, PlatformCookie);
159  Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
160  Stream_Read_UINT32(ifman->input, numMediaType);
161  DEBUG_TSMF("PlatformCookie %" PRIu32 " numMediaType %" PRIu32 "", PlatformCookie, numMediaType);
162 
163  if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input))
164  FormatSupported = 0;
165 
166  if (FormatSupported)
167  DEBUG_TSMF("format ok.");
168 
169  if (!Stream_EnsureRemainingCapacity(ifman->output, 12))
170  return -1;
171 
172  Stream_Write_UINT32(ifman->output, FormatSupported);
173  Stream_Write_UINT32(ifman->output, PlatformCookie);
174  Stream_Write_UINT32(ifman->output, 0); /* Result */
175  ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
176  return CHANNEL_RC_OK;
177 }
178 
184 UINT tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
185 {
186  UINT status = CHANNEL_RC_OK;
187  TSMF_PRESENTATION* presentation = NULL;
188  DEBUG_TSMF("");
189 
190  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE))
191  return ERROR_INVALID_DATA;
192 
193  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
194 
195  if (presentation)
196  {
197  DEBUG_TSMF("Presentation already exists");
198  ifman->output_pending = FALSE;
199  return CHANNEL_RC_OK;
200  }
201 
202  presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback);
203 
204  if (!presentation)
205  status = ERROR_OUTOFMEMORY;
206  else
207  tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
208 
209  ifman->output_pending = TRUE;
210  return status;
211 }
212 
218 UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
219 {
220  UINT32 StreamId = 0;
221  UINT status = CHANNEL_RC_OK;
222  TSMF_STREAM* stream = NULL;
223  TSMF_PRESENTATION* presentation = NULL;
224  DEBUG_TSMF("");
225 
226  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE + 8))
227  return ERROR_INVALID_DATA;
228 
229  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
230  Stream_Seek(ifman->input, GUID_SIZE);
231 
232  if (!presentation)
233  {
234  WLog_ERR(TAG, "unknown presentation id");
235  status = ERROR_NOT_FOUND;
236  }
237  else
238  {
239  Stream_Read_UINT32(ifman->input, StreamId);
240  Stream_Seek_UINT32(ifman->input); /* numMediaType */
241  stream = tsmf_stream_new(presentation, StreamId, rdpcontext);
242 
243  if (!stream)
244  {
245  WLog_ERR(TAG, "failed to create stream");
246  return ERROR_OUTOFMEMORY;
247  }
248 
249  if (!tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input))
250  {
251  WLog_ERR(TAG, "failed to set stream format");
252  return ERROR_OUTOFMEMORY;
253  }
254 
255  tsmf_stream_start_threads(stream);
256  }
257 
258  ifman->output_pending = TRUE;
259  return status;
260 }
261 
267 UINT tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
268 {
269  DEBUG_TSMF("");
270 
271  if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
272  return ERROR_OUTOFMEMORY;
273 
274  Stream_Write_UINT32(ifman->output, 1); /* TopologyReady */
275  Stream_Write_UINT32(ifman->output, 0); /* Result */
276  ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
277  return CHANNEL_RC_OK;
278 }
279 
285 UINT tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
286 {
287  int status = CHANNEL_RC_OK;
288  UINT32 StreamId = 0;
289  TSMF_STREAM* stream = NULL;
290  TSMF_PRESENTATION* presentation = NULL;
291  DEBUG_TSMF("");
292 
293  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 20))
294  return ERROR_INVALID_DATA;
295 
296  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
297  Stream_Seek(ifman->input, GUID_SIZE);
298 
299  if (!presentation)
300  {
301  status = ERROR_NOT_FOUND;
302  }
303  else
304  {
305  Stream_Read_UINT32(ifman->input, StreamId);
306  stream = tsmf_stream_find_by_id(presentation, StreamId);
307 
308  if (stream)
309  tsmf_stream_free(stream);
310  else
311  status = ERROR_NOT_FOUND;
312  }
313 
314  ifman->output_pending = TRUE;
315  return status;
316 }
317 
318 static float tsmf_stream_read_float(wStream* s)
319 {
320  float fValue = NAN;
321  UINT32 iValue = 0;
322  Stream_Read_UINT32(s, iValue);
323  CopyMemory(&fValue, &iValue, 4);
324  return fValue;
325 }
326 
332 UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
333 {
334  UINT status = CHANNEL_RC_OK;
335  float Left = NAN;
336  float Top = NAN;
337  float Right = NAN;
338  float Bottom = NAN;
339  TSMF_PRESENTATION* presentation = NULL;
340  DEBUG_TSMF("");
341 
342  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 32))
343  return ERROR_INVALID_DATA;
344 
345  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
346  Stream_Seek(ifman->input, GUID_SIZE);
347 
348  if (!presentation)
349  {
350  status = ERROR_NOT_FOUND;
351  }
352  else
353  {
354  Left = tsmf_stream_read_float(ifman->input); /* Left (4 bytes) */
355  Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */
356  Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */
357  Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */
358  DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f", Left, Top, Right,
359  Bottom);
360  }
361 
362  ifman->output_pending = TRUE;
363  return status;
364 }
365 
371 UINT tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
372 {
373  TSMF_PRESENTATION* presentation = NULL;
374  DEBUG_TSMF("");
375 
376  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE))
377  return ERROR_INVALID_DATA;
378 
379  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
380 
381  if (presentation)
382  tsmf_presentation_free(presentation);
383  else
384  {
385  WLog_ERR(TAG, "unknown presentation id");
386  return ERROR_NOT_FOUND;
387  }
388 
389  if (!Stream_EnsureRemainingCapacity(ifman->output, 4))
390  return ERROR_OUTOFMEMORY;
391 
392  Stream_Write_UINT32(ifman->output, 0); /* Result */
393  ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
394  return CHANNEL_RC_OK;
395 }
396 
402 UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
403 {
404  TSMF_PRESENTATION* presentation = NULL;
405  UINT32 newVolume = 0;
406  UINT32 muted = 0;
407  DEBUG_TSMF("on stream volume");
408 
409  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE + 8))
410  return ERROR_INVALID_DATA;
411 
412  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
413 
414  if (!presentation)
415  {
416  WLog_ERR(TAG, "unknown presentation id");
417  return ERROR_NOT_FOUND;
418  }
419 
420  Stream_Seek(ifman->input, 16);
421  Stream_Read_UINT32(ifman->input, newVolume);
422  DEBUG_TSMF("on stream volume: new volume=[%" PRIu32 "]", newVolume);
423  Stream_Read_UINT32(ifman->input, muted);
424  DEBUG_TSMF("on stream volume: muted=[%" PRIu32 "]", muted);
425 
426  if (!tsmf_presentation_volume_changed(presentation, newVolume, muted))
427  return ERROR_INVALID_OPERATION;
428 
429  ifman->output_pending = TRUE;
430  return 0;
431 }
432 
438 UINT tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
439 {
440  TSMF_PRESENTATION* presentation = NULL;
441  DEBUG_TSMF("on channel volume");
442 
443  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE + 8))
444  return ERROR_INVALID_DATA;
445 
446  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
447 
448  if (presentation)
449  {
450  UINT32 channelVolume = 0;
451  UINT32 changedChannel = 0;
452  Stream_Seek(ifman->input, 16);
453  Stream_Read_UINT32(ifman->input, channelVolume);
454  DEBUG_TSMF("on channel volume: channel volume=[%" PRIu32 "]", channelVolume);
455  Stream_Read_UINT32(ifman->input, changedChannel);
456  DEBUG_TSMF("on stream volume: changed channel=[%" PRIu32 "]", changedChannel);
457  }
458 
459  ifman->output_pending = TRUE;
460  return CHANNEL_RC_OK;
461 }
462 
468 UINT tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
469 {
470  DEBUG_TSMF("");
471  ifman->output_pending = TRUE;
472  return CHANNEL_RC_OK;
473 }
474 
480 UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
481 {
482  TSMF_PRESENTATION* presentation = NULL;
483  UINT32 numGeometryInfo = 0;
484  UINT32 Left = 0;
485  UINT32 Top = 0;
486  UINT32 Width = 0;
487  UINT32 Height = 0;
488  UINT32 cbVisibleRect = 0;
489  RECTANGLE_32* rects = NULL;
490  UINT error = CHANNEL_RC_OK;
491  size_t pos = 0;
492 
493  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE + 32))
494  return ERROR_INVALID_DATA;
495 
496  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
497 
498  if (!presentation)
499  return ERROR_NOT_FOUND;
500 
501  Stream_Seek(ifman->input, 16);
502  Stream_Read_UINT32(ifman->input, numGeometryInfo);
503  pos = Stream_GetPosition(ifman->input);
504  Stream_Seek(ifman->input, 12); /* VideoWindowId (8 bytes), VideoWindowState (4 bytes) */
505  Stream_Read_UINT32(ifman->input, Width);
506  Stream_Read_UINT32(ifman->input, Height);
507  Stream_Read_UINT32(ifman->input, Left);
508  Stream_Read_UINT32(ifman->input, Top);
509  Stream_SetPosition(ifman->input, pos + numGeometryInfo);
510  Stream_Read_UINT32(ifman->input, cbVisibleRect);
511  const UINT32 num_rects = cbVisibleRect / 16;
512  DEBUG_TSMF("numGeometryInfo %" PRIu32 " Width %" PRIu32 " Height %" PRIu32 " Left %" PRIu32
513  " Top %" PRIu32 " cbVisibleRect %" PRIu32 " num_rects %d",
514  numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
515 
516  if (num_rects > 0)
517  {
518  rects = (RECTANGLE_32*)calloc(num_rects, sizeof(RECTANGLE_32));
519 
520  for (size_t i = 0; i < num_rects; i++)
521  {
522  Stream_Read_UINT32(ifman->input, rects[i].top); /* Top */
523  Stream_Read_UINT32(ifman->input, rects[i].left); /* Left */
524  Stream_Read_UINT32(ifman->input, rects[i].height); /* Bottom */
525  Stream_Read_UINT32(ifman->input, rects[i].width); /* Right */
526  rects[i].width -= rects[i].left;
527  rects[i].height -= rects[i].top;
528  DEBUG_TSMF("rect %d: %" PRId16 " %" PRId16 " %" PRId16 " %" PRId16 "", i, rects[i].x,
529  rects[i].y, rects[i].width, rects[i].height);
530  }
531  }
532 
533  const BOOL rc = tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height,
534  num_rects, rects);
535  free(rects);
536  if (!rc)
537  return ERROR_INVALID_OPERATION;
538 
539  ifman->output_pending = TRUE;
540  return error;
541 }
542 
548 UINT tsmf_ifman_set_allocator(TSMF_IFMAN* ifman)
549 {
550  DEBUG_TSMF("");
551  ifman->output_pending = TRUE;
552  return CHANNEL_RC_OK;
553 }
554 
560 UINT tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman)
561 {
562  DEBUG_TSMF("");
563  tsmf_ifman_on_playback_paused(ifman);
564  ifman->output_pending = TRUE;
565  return CHANNEL_RC_OK;
566 }
567 
573 UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
574 {
575  TSMF_PRESENTATION* presentation = NULL;
576  TSMF_STREAM* stream = NULL;
577  UINT32 StreamId = 0;
578  UINT64 SampleStartTime = 0;
579  UINT64 SampleEndTime = 0;
580  UINT64 ThrottleDuration = 0;
581  UINT32 SampleExtensions = 0;
582  UINT32 cbData = 0;
583  UINT error = 0;
584 
585  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 60))
586  return ERROR_INVALID_DATA;
587 
588  Stream_Seek(ifman->input, 16);
589  Stream_Read_UINT32(ifman->input, StreamId);
590  Stream_Seek_UINT32(ifman->input); /* numSample */
591  Stream_Read_UINT64(ifman->input, SampleStartTime);
592  Stream_Read_UINT64(ifman->input, SampleEndTime);
593  Stream_Read_UINT64(ifman->input, ThrottleDuration);
594  Stream_Seek_UINT32(ifman->input); /* SampleFlags */
595  Stream_Read_UINT32(ifman->input, SampleExtensions);
596  Stream_Read_UINT32(ifman->input, cbData);
597 
598  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, cbData))
599  return ERROR_INVALID_DATA;
600 
601  DEBUG_TSMF("MessageId %" PRIu32 " StreamId %" PRIu32 " SampleStartTime %" PRIu64
602  " SampleEndTime %" PRIu64 " "
603  "ThrottleDuration %" PRIu64 " SampleExtensions %" PRIu32 " cbData %" PRIu32 "",
604  ifman->message_id, StreamId, SampleStartTime, SampleEndTime, ThrottleDuration,
605  SampleExtensions, cbData);
606  presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
607 
608  if (!presentation)
609  {
610  WLog_ERR(TAG, "unknown presentation id");
611  return ERROR_NOT_FOUND;
612  }
613 
614  stream = tsmf_stream_find_by_id(presentation, StreamId);
615 
616  if (!stream)
617  {
618  WLog_ERR(TAG, "unknown stream id");
619  return ERROR_NOT_FOUND;
620  }
621 
622  if (!tsmf_stream_push_sample(stream, ifman->channel_callback, ifman->message_id,
623  SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
624  cbData, Stream_Pointer(ifman->input)))
625  {
626  WLog_ERR(TAG, "unable to push sample");
627  return ERROR_OUTOFMEMORY;
628  }
629 
630  if ((error = tsmf_presentation_sync(presentation)))
631  {
632  WLog_ERR(TAG, "tsmf_presentation_sync failed with error %" PRIu32 "", error);
633  return error;
634  }
635 
636  ifman->output_pending = TRUE;
637  return CHANNEL_RC_OK;
638 }
639 
645 UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
646 {
647  UINT32 StreamId = 0;
648  TSMF_PRESENTATION* presentation = NULL;
649  TSMF_STREAM* stream = NULL;
650 
651  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 20))
652  return ERROR_INVALID_DATA;
653 
654  Stream_Seek(ifman->input, 16);
655  Stream_Read_UINT32(ifman->input, StreamId);
656  DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
657  presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
658 
659  if (!presentation)
660  {
661  WLog_ERR(TAG, "unknown presentation id");
662  return ERROR_NOT_FOUND;
663  }
664 
665  /* Flush message is for a stream, not the entire presentation
666  * therefore we only flush the stream as intended per the MS-RDPEV spec
667  */
668  stream = tsmf_stream_find_by_id(presentation, StreamId);
669 
670  if (stream)
671  {
672  if (!tsmf_stream_flush(stream))
673  return ERROR_INVALID_OPERATION;
674  }
675  else
676  WLog_ERR(TAG, "unknown stream id");
677 
678  ifman->output_pending = TRUE;
679  return CHANNEL_RC_OK;
680 }
681 
687 UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
688 {
689  UINT32 StreamId = 0;
690  TSMF_STREAM* stream = NULL;
691  TSMF_PRESENTATION* presentation = NULL;
692 
693  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 20))
694  return ERROR_INVALID_DATA;
695 
696  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
697  Stream_Seek(ifman->input, 16);
698  Stream_Read_UINT32(ifman->input, StreamId);
699 
700  if (presentation)
701  {
702  stream = tsmf_stream_find_by_id(presentation, StreamId);
703 
704  if (stream)
705  tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
706  }
707 
708  DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
709  ifman->output_pending = TRUE;
710  ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
711  return CHANNEL_RC_OK;
712 }
713 
719 UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
720 {
721  TSMF_PRESENTATION* presentation = NULL;
722  DEBUG_TSMF("");
723 
724  if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 16))
725  return ERROR_INVALID_DATA;
726 
727  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
728 
729  if (presentation)
730  tsmf_presentation_start(presentation);
731  else
732  WLog_ERR(TAG, "unknown presentation id");
733 
734  if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
735  return ERROR_OUTOFMEMORY;
736 
737  Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
738  Stream_Write_UINT32(ifman->output, 0); /* StreamId */
739  Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
740  Stream_Write_UINT32(ifman->output, 0); /* cbData */
741  ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
742  return CHANNEL_RC_OK;
743 }
744 
750 UINT tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
751 {
752  TSMF_PRESENTATION* presentation = NULL;
753  DEBUG_TSMF("");
754  ifman->output_pending = TRUE;
755  /* Added pause control so gstreamer pipeline can be paused accordingly */
756  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
757 
758  if (presentation)
759  {
760  if (!tsmf_presentation_paused(presentation))
761  return ERROR_INVALID_OPERATION;
762  }
763  else
764  WLog_ERR(TAG, "unknown presentation id");
765 
766  return CHANNEL_RC_OK;
767 }
768 
774 UINT tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
775 {
776  TSMF_PRESENTATION* presentation = NULL;
777  DEBUG_TSMF("");
778  ifman->output_pending = TRUE;
779  /* Added restart control so gstreamer pipeline can be resumed accordingly */
780  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
781 
782  if (presentation)
783  {
784  if (!tsmf_presentation_restarted(presentation))
785  return ERROR_INVALID_OPERATION;
786  }
787  else
788  WLog_ERR(TAG, "unknown presentation id");
789 
790  return CHANNEL_RC_OK;
791 }
792 
798 UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
799 {
800  TSMF_PRESENTATION* presentation = NULL;
801  DEBUG_TSMF("");
802  presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
803 
804  if (presentation)
805  {
806  if (!tsmf_presentation_stop(presentation))
807  return ERROR_INVALID_OPERATION;
808  }
809  else
810  WLog_ERR(TAG, "unknown presentation id");
811 
812  if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
813  return ERROR_OUTOFMEMORY;
814 
815  Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
816  Stream_Write_UINT32(ifman->output, 0); /* StreamId */
817  Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */
818  Stream_Write_UINT32(ifman->output, 0); /* cbData */
819  ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
820  return CHANNEL_RC_OK;
821 }
822 
828 UINT tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman)
829 {
830  DEBUG_TSMF("");
831 
832  if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
833  return ERROR_OUTOFMEMORY;
834 
835  Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
836  Stream_Write_UINT32(ifman->output, 0); /* StreamId */
837  Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_MONITORCHANGED); /* EventId */
838  Stream_Write_UINT32(ifman->output, 0); /* cbData */
839  ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
840  return CHANNEL_RC_OK;
841 }