FreeRDP
Loading...
Searching...
No Matches
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
46UINT 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
69UINT 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
149UINT 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
184UINT 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
218UINT 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
267UINT 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
285UINT 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
318static 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
332UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
333{
334 UINT status = CHANNEL_RC_OK;
335 TSMF_PRESENTATION* presentation = NULL;
336 DEBUG_TSMF("");
337
338 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 32))
339 return ERROR_INVALID_DATA;
340
341 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
342 Stream_Seek(ifman->input, GUID_SIZE);
343
344 if (!presentation)
345 {
346 status = ERROR_NOT_FOUND;
347 }
348 else
349 {
350#ifdef WITH_DEBUG_TSMF
351 const float Left = tsmf_stream_read_float(ifman->input); /* Left (4 bytes) */
352 const float Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */
353 const float Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */
354 const float Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */
355 DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f", Left, Top, Right,
356 Bottom);
357#endif
358 }
359
360 ifman->output_pending = TRUE;
361 return status;
362}
363
369UINT tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
370{
371 TSMF_PRESENTATION* presentation = NULL;
372 DEBUG_TSMF("");
373
374 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE))
375 return ERROR_INVALID_DATA;
376
377 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
378
379 if (presentation)
380 tsmf_presentation_free(presentation);
381 else
382 {
383 WLog_ERR(TAG, "unknown presentation id");
384 return ERROR_NOT_FOUND;
385 }
386
387 if (!Stream_EnsureRemainingCapacity(ifman->output, 4))
388 return ERROR_OUTOFMEMORY;
389
390 Stream_Write_UINT32(ifman->output, 0); /* Result */
391 ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
392 return CHANNEL_RC_OK;
393}
394
400UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
401{
402 TSMF_PRESENTATION* presentation = NULL;
403 UINT32 newVolume = 0;
404 UINT32 muted = 0;
405 DEBUG_TSMF("on stream volume");
406
407 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE + 8))
408 return ERROR_INVALID_DATA;
409
410 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
411
412 if (!presentation)
413 {
414 WLog_ERR(TAG, "unknown presentation id");
415 return ERROR_NOT_FOUND;
416 }
417
418 Stream_Seek(ifman->input, 16);
419 Stream_Read_UINT32(ifman->input, newVolume);
420 DEBUG_TSMF("on stream volume: new volume=[%" PRIu32 "]", newVolume);
421 Stream_Read_UINT32(ifman->input, muted);
422 DEBUG_TSMF("on stream volume: muted=[%" PRIu32 "]", muted);
423
424 if (!tsmf_presentation_volume_changed(presentation, newVolume, muted))
425 return ERROR_INVALID_OPERATION;
426
427 ifman->output_pending = TRUE;
428 return 0;
429}
430
436UINT tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
437{
438 TSMF_PRESENTATION* presentation = NULL;
439 DEBUG_TSMF("on channel volume");
440
441 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE + 8))
442 return ERROR_INVALID_DATA;
443
444 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
445
446 if (presentation)
447 {
448 UINT32 channelVolume = 0;
449 UINT32 changedChannel = 0;
450 Stream_Seek(ifman->input, 16);
451 Stream_Read_UINT32(ifman->input, channelVolume);
452 DEBUG_TSMF("on channel volume: channel volume=[%" PRIu32 "]", channelVolume);
453 Stream_Read_UINT32(ifman->input, changedChannel);
454 DEBUG_TSMF("on stream volume: changed channel=[%" PRIu32 "]", changedChannel);
455 }
456
457 ifman->output_pending = TRUE;
458 return CHANNEL_RC_OK;
459}
460
466UINT tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
467{
468 DEBUG_TSMF("");
469 ifman->output_pending = TRUE;
470 return CHANNEL_RC_OK;
471}
472
478UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
479{
480 TSMF_PRESENTATION* presentation = NULL;
481 UINT32 numGeometryInfo = 0;
482 UINT32 Left = 0;
483 UINT32 Top = 0;
484 UINT32 Width = 0;
485 UINT32 Height = 0;
486 UINT32 cbVisibleRect = 0;
487 RECTANGLE_32* rects = NULL;
488 UINT error = CHANNEL_RC_OK;
489 size_t pos = 0;
490
491 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE + 32))
492 return ERROR_INVALID_DATA;
493
494 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
495
496 if (!presentation)
497 return ERROR_NOT_FOUND;
498
499 Stream_Seek(ifman->input, 16);
500 Stream_Read_UINT32(ifman->input, numGeometryInfo);
501 pos = Stream_GetPosition(ifman->input);
502 Stream_Seek(ifman->input, 12); /* VideoWindowId (8 bytes), VideoWindowState (4 bytes) */
503 Stream_Read_UINT32(ifman->input, Width);
504 Stream_Read_UINT32(ifman->input, Height);
505 Stream_Read_UINT32(ifman->input, Left);
506 Stream_Read_UINT32(ifman->input, Top);
507 Stream_SetPosition(ifman->input, pos + numGeometryInfo);
508 Stream_Read_UINT32(ifman->input, cbVisibleRect);
509 const UINT32 num_rects = cbVisibleRect / 16;
510 DEBUG_TSMF("numGeometryInfo %" PRIu32 " Width %" PRIu32 " Height %" PRIu32 " Left %" PRIu32
511 " Top %" PRIu32 " cbVisibleRect %" PRIu32 " num_rects %d",
512 numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
513
514 if (num_rects > 0)
515 {
516 rects = (RECTANGLE_32*)calloc(num_rects, sizeof(RECTANGLE_32));
517
518 for (size_t i = 0; i < num_rects; i++)
519 {
520 Stream_Read_UINT32(ifman->input, rects[i].top); /* Top */
521 Stream_Read_UINT32(ifman->input, rects[i].left); /* Left */
522 Stream_Read_UINT32(ifman->input, rects[i].height); /* Bottom */
523 Stream_Read_UINT32(ifman->input, rects[i].width); /* Right */
524 rects[i].width -= rects[i].left;
525 rects[i].height -= rects[i].top;
526 DEBUG_TSMF("rect %d: %" PRId16 " %" PRId16 " %" PRId16 " %" PRId16 "", i, rects[i].x,
527 rects[i].y, rects[i].width, rects[i].height);
528 }
529 }
530
531 const BOOL rc = tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height,
532 num_rects, rects);
533 free(rects);
534 if (!rc)
535 return ERROR_INVALID_OPERATION;
536
537 ifman->output_pending = TRUE;
538 return error;
539}
540
546UINT tsmf_ifman_set_allocator(TSMF_IFMAN* ifman)
547{
548 DEBUG_TSMF("");
549 ifman->output_pending = TRUE;
550 return CHANNEL_RC_OK;
551}
552
558UINT tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman)
559{
560 DEBUG_TSMF("");
561 tsmf_ifman_on_playback_paused(ifman);
562 ifman->output_pending = TRUE;
563 return CHANNEL_RC_OK;
564}
565
571UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
572{
573 TSMF_PRESENTATION* presentation = NULL;
574 TSMF_STREAM* stream = NULL;
575 UINT32 StreamId = 0;
576 UINT64 SampleStartTime = 0;
577 UINT64 SampleEndTime = 0;
578 UINT64 ThrottleDuration = 0;
579 UINT32 SampleExtensions = 0;
580 UINT32 cbData = 0;
581 UINT error = 0;
582
583 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 60))
584 return ERROR_INVALID_DATA;
585
586 Stream_Seek(ifman->input, 16);
587 Stream_Read_UINT32(ifman->input, StreamId);
588 Stream_Seek_UINT32(ifman->input); /* numSample */
589 Stream_Read_UINT64(ifman->input, SampleStartTime);
590 Stream_Read_UINT64(ifman->input, SampleEndTime);
591 Stream_Read_UINT64(ifman->input, ThrottleDuration);
592 Stream_Seek_UINT32(ifman->input); /* SampleFlags */
593 Stream_Read_UINT32(ifman->input, SampleExtensions);
594 Stream_Read_UINT32(ifman->input, cbData);
595
596 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, cbData))
597 return ERROR_INVALID_DATA;
598
599 DEBUG_TSMF("MessageId %" PRIu32 " StreamId %" PRIu32 " SampleStartTime %" PRIu64
600 " SampleEndTime %" PRIu64 " "
601 "ThrottleDuration %" PRIu64 " SampleExtensions %" PRIu32 " cbData %" PRIu32 "",
602 ifman->message_id, StreamId, SampleStartTime, SampleEndTime, ThrottleDuration,
603 SampleExtensions, cbData);
604 presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
605
606 if (!presentation)
607 {
608 WLog_ERR(TAG, "unknown presentation id");
609 return ERROR_NOT_FOUND;
610 }
611
612 stream = tsmf_stream_find_by_id(presentation, StreamId);
613
614 if (!stream)
615 {
616 WLog_ERR(TAG, "unknown stream id");
617 return ERROR_NOT_FOUND;
618 }
619
620 if (!tsmf_stream_push_sample(stream, ifman->channel_callback, ifman->message_id,
621 SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
622 cbData, Stream_Pointer(ifman->input)))
623 {
624 WLog_ERR(TAG, "unable to push sample");
625 return ERROR_OUTOFMEMORY;
626 }
627
628 if ((error = tsmf_presentation_sync(presentation)))
629 {
630 WLog_ERR(TAG, "tsmf_presentation_sync failed with error %" PRIu32 "", error);
631 return error;
632 }
633
634 ifman->output_pending = TRUE;
635 return CHANNEL_RC_OK;
636}
637
643UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
644{
645 UINT32 StreamId = 0;
646 TSMF_PRESENTATION* presentation = NULL;
647 TSMF_STREAM* stream = NULL;
648
649 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 20))
650 return ERROR_INVALID_DATA;
651
652 Stream_Seek(ifman->input, 16);
653 Stream_Read_UINT32(ifman->input, StreamId);
654 DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
655 presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
656
657 if (!presentation)
658 {
659 WLog_ERR(TAG, "unknown presentation id");
660 return ERROR_NOT_FOUND;
661 }
662
663 /* Flush message is for a stream, not the entire presentation
664 * therefore we only flush the stream as intended per the MS-RDPEV spec
665 */
666 stream = tsmf_stream_find_by_id(presentation, StreamId);
667
668 if (stream)
669 {
670 if (!tsmf_stream_flush(stream))
671 return ERROR_INVALID_OPERATION;
672 }
673 else
674 WLog_ERR(TAG, "unknown stream id");
675
676 ifman->output_pending = TRUE;
677 return CHANNEL_RC_OK;
678}
679
685UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
686{
687 UINT32 StreamId = 0;
688 TSMF_STREAM* stream = NULL;
689 TSMF_PRESENTATION* presentation = NULL;
690
691 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 20))
692 return ERROR_INVALID_DATA;
693
694 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
695 Stream_Seek(ifman->input, 16);
696 Stream_Read_UINT32(ifman->input, StreamId);
697
698 if (presentation)
699 {
700 stream = tsmf_stream_find_by_id(presentation, StreamId);
701
702 if (stream)
703 tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
704 }
705
706 DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
707 ifman->output_pending = TRUE;
708 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
709 return CHANNEL_RC_OK;
710}
711
717UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
718{
719 TSMF_PRESENTATION* presentation = NULL;
720 DEBUG_TSMF("");
721
722 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 16))
723 return ERROR_INVALID_DATA;
724
725 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
726
727 if (presentation)
728 tsmf_presentation_start(presentation);
729 else
730 WLog_ERR(TAG, "unknown presentation id");
731
732 if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
733 return ERROR_OUTOFMEMORY;
734
735 Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
736 Stream_Write_UINT32(ifman->output, 0); /* StreamId */
737 Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
738 Stream_Write_UINT32(ifman->output, 0); /* cbData */
739 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
740 return CHANNEL_RC_OK;
741}
742
748UINT tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
749{
750 TSMF_PRESENTATION* presentation = NULL;
751 DEBUG_TSMF("");
752 ifman->output_pending = TRUE;
753 /* Added pause control so gstreamer pipeline can be paused accordingly */
754 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
755
756 if (presentation)
757 {
758 if (!tsmf_presentation_paused(presentation))
759 return ERROR_INVALID_OPERATION;
760 }
761 else
762 WLog_ERR(TAG, "unknown presentation id");
763
764 return CHANNEL_RC_OK;
765}
766
772UINT tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
773{
774 TSMF_PRESENTATION* presentation = NULL;
775 DEBUG_TSMF("");
776 ifman->output_pending = TRUE;
777 /* Added restart control so gstreamer pipeline can be resumed accordingly */
778 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
779
780 if (presentation)
781 {
782 if (!tsmf_presentation_restarted(presentation))
783 return ERROR_INVALID_OPERATION;
784 }
785 else
786 WLog_ERR(TAG, "unknown presentation id");
787
788 return CHANNEL_RC_OK;
789}
790
796UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
797{
798 TSMF_PRESENTATION* presentation = NULL;
799 DEBUG_TSMF("");
800 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
801
802 if (presentation)
803 {
804 if (!tsmf_presentation_stop(presentation))
805 return ERROR_INVALID_OPERATION;
806 }
807 else
808 WLog_ERR(TAG, "unknown presentation id");
809
810 if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
811 return ERROR_OUTOFMEMORY;
812
813 Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
814 Stream_Write_UINT32(ifman->output, 0); /* StreamId */
815 Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */
816 Stream_Write_UINT32(ifman->output, 0); /* cbData */
817 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
818 return CHANNEL_RC_OK;
819}
820
826UINT tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman)
827{
828 DEBUG_TSMF("");
829
830 if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
831 return ERROR_OUTOFMEMORY;
832
833 Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
834 Stream_Write_UINT32(ifman->output, 0); /* StreamId */
835 Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_MONITORCHANGED); /* EventId */
836 Stream_Write_UINT32(ifman->output, 0); /* cbData */
837 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
838 return CHANNEL_RC_OK;
839}