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 if (!Stream_SetPosition(ifman->output, xpos))
85 return ERROR_INVALID_DATA;
86
87 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, 4))
88 return ERROR_INVALID_DATA;
89
90 Stream_Read_UINT32(ifman->output, numHostCapabilities);
91
92 for (UINT32 i = 0; i < numHostCapabilities; i++)
93 {
94 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, 8))
95 return ERROR_INVALID_DATA;
96
97 Stream_Read_UINT32(ifman->output, CapabilityType);
98 Stream_Read_UINT32(ifman->output, cbCapabilityLength);
99
100 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, cbCapabilityLength))
101 return ERROR_INVALID_DATA;
102
103 const size_t pos = Stream_GetPosition(ifman->output);
104
105 switch (CapabilityType)
106 {
107 case 1: /* Protocol version request */
108 {
109 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, 4))
110 return ERROR_INVALID_DATA;
111
112 const UINT32 v = Stream_Get_UINT32(ifman->output);
113 WINPR_UNUSED(v);
114 DEBUG_TSMF("server protocol version %" PRIu32 "", v);
115 }
116 break;
117
118 case 2: /* Supported platform */
119 {
120 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->output, 4))
121 return ERROR_INVALID_DATA;
122
123 const UINT32 v = Stream_Get_UINT32(ifman->output);
124 WINPR_UNUSED(v);
125 DEBUG_TSMF("server supported platform %" PRIu32 "", v);
126 /* Claim that we support both MF and DShow platforms. */
127 Stream_Write_UINT32(ifman->output, MMREDIR_CAPABILITY_PLATFORM_MF |
128 MMREDIR_CAPABILITY_PLATFORM_DSHOW);
129 }
130 break;
131
132 default:
133 WLog_ERR(TAG, "skipping unknown capability type %" PRIu32 "", CapabilityType);
134 break;
135 }
136
137 if (!Stream_SetPosition(ifman->output, pos + cbCapabilityLength))
138 return ERROR_INVALID_DATA;
139 }
140
141 Stream_Write_UINT32(ifman->output, 0); /* Result */
142 ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
143 return CHANNEL_RC_OK;
144}
145
151UINT tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
152{
153 UINT32 numMediaType = 0;
154 UINT32 PlatformCookie = 0;
155 UINT32 FormatSupported = 1;
156
157 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 12))
158 return ERROR_INVALID_DATA;
159
160 Stream_Read_UINT32(ifman->input, PlatformCookie);
161 Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
162 Stream_Read_UINT32(ifman->input, numMediaType);
163 DEBUG_TSMF("PlatformCookie %" PRIu32 " numMediaType %" PRIu32 "", PlatformCookie, numMediaType);
164
165 if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input))
166 FormatSupported = 0;
167
168 if (FormatSupported)
169 DEBUG_TSMF("format ok.");
170
171 if (!Stream_EnsureRemainingCapacity(ifman->output, 12))
172 return -1;
173
174 Stream_Write_UINT32(ifman->output, FormatSupported);
175 Stream_Write_UINT32(ifman->output, PlatformCookie);
176 Stream_Write_UINT32(ifman->output, 0); /* Result */
177 ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
178 return CHANNEL_RC_OK;
179}
180
186UINT tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
187{
188 UINT status = CHANNEL_RC_OK;
189 TSMF_PRESENTATION* presentation = nullptr;
190 DEBUG_TSMF("");
191
192 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE))
193 return ERROR_INVALID_DATA;
194
195 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
196
197 if (presentation)
198 {
199 DEBUG_TSMF("Presentation already exists");
200 ifman->output_pending = FALSE;
201 return CHANNEL_RC_OK;
202 }
203
204 presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback);
205
206 if (!presentation)
207 status = ERROR_OUTOFMEMORY;
208 else
209 tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
210
211 ifman->output_pending = TRUE;
212 return status;
213}
214
220UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
221{
222 UINT32 StreamId = 0;
223 UINT status = CHANNEL_RC_OK;
224 TSMF_STREAM* stream = nullptr;
225 TSMF_PRESENTATION* presentation = nullptr;
226 DEBUG_TSMF("");
227
228 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, GUID_SIZE + 8))
229 return ERROR_INVALID_DATA;
230
231 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
232 Stream_Seek(ifman->input, GUID_SIZE);
233
234 if (!presentation)
235 {
236 WLog_ERR(TAG, "unknown presentation id");
237 status = ERROR_NOT_FOUND;
238 }
239 else
240 {
241 Stream_Read_UINT32(ifman->input, StreamId);
242 Stream_Seek_UINT32(ifman->input); /* numMediaType */
243 stream = tsmf_stream_new(presentation, StreamId, rdpcontext);
244
245 if (!stream)
246 {
247 WLog_ERR(TAG, "failed to create stream");
248 return ERROR_OUTOFMEMORY;
249 }
250
251 if (!tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input))
252 {
253 WLog_ERR(TAG, "failed to set stream format");
254 return ERROR_OUTOFMEMORY;
255 }
256
257 tsmf_stream_start_threads(stream);
258 }
259
260 ifman->output_pending = TRUE;
261 return status;
262}
263
269UINT tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
270{
271 DEBUG_TSMF("");
272
273 if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
274 return ERROR_OUTOFMEMORY;
275
276 Stream_Write_UINT32(ifman->output, 1); /* TopologyReady */
277 Stream_Write_UINT32(ifman->output, 0); /* Result */
278 ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
279 return CHANNEL_RC_OK;
280}
281
287UINT tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
288{
289 int status = CHANNEL_RC_OK;
290 UINT32 StreamId = 0;
291 TSMF_STREAM* stream = nullptr;
292 TSMF_PRESENTATION* presentation = nullptr;
293 DEBUG_TSMF("");
294
295 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 20))
296 return ERROR_INVALID_DATA;
297
298 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
299 Stream_Seek(ifman->input, GUID_SIZE);
300
301 if (!presentation)
302 {
303 status = ERROR_NOT_FOUND;
304 }
305 else
306 {
307 Stream_Read_UINT32(ifman->input, StreamId);
308 stream = tsmf_stream_find_by_id(presentation, StreamId);
309
310 if (stream)
311 tsmf_stream_free(stream);
312 else
313 status = ERROR_NOT_FOUND;
314 }
315
316 ifman->output_pending = TRUE;
317 return status;
318}
319
320static float tsmf_stream_read_float(wStream* s)
321{
322 float fValue = NAN;
323 UINT32 iValue = 0;
324 Stream_Read_UINT32(s, iValue);
325 CopyMemory(&fValue, &iValue, 4);
326 return fValue;
327}
328
334UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
335{
336 UINT status = CHANNEL_RC_OK;
337 TSMF_PRESENTATION* presentation = nullptr;
338 DEBUG_TSMF("");
339
340 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 32))
341 return ERROR_INVALID_DATA;
342
343 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
344 Stream_Seek(ifman->input, GUID_SIZE);
345
346 if (!presentation)
347 {
348 status = ERROR_NOT_FOUND;
349 }
350 else
351 {
352#ifdef WITH_DEBUG_TSMF
353 const float Left = tsmf_stream_read_float(ifman->input); /* Left (4 bytes) */
354 const float Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */
355 const float Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */
356 const float Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */
357 DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f", Left, Top, Right,
358 Bottom);
359#endif
360 }
361
362 ifman->output_pending = TRUE;
363 return status;
364}
365
371UINT tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
372{
373 TSMF_PRESENTATION* presentation = nullptr;
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
402UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
403{
404 TSMF_PRESENTATION* presentation = nullptr;
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
438UINT tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
439{
440 TSMF_PRESENTATION* presentation = nullptr;
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
468UINT tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
469{
470 DEBUG_TSMF("");
471 ifman->output_pending = TRUE;
472 return CHANNEL_RC_OK;
473}
474
480UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
481{
482 TSMF_PRESENTATION* presentation = nullptr;
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 = nullptr;
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 if (!Stream_SetPosition(ifman->input, pos + numGeometryInfo))
510 return ERROR_INVALID_DATA;
511 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 4))
512 return ERROR_INVALID_DATA;
513 Stream_Read_UINT32(ifman->input, cbVisibleRect);
514 const UINT32 num_rects = cbVisibleRect / 16;
515 DEBUG_TSMF("numGeometryInfo %" PRIu32 " Width %" PRIu32 " Height %" PRIu32 " Left %" PRIu32
516 " Top %" PRIu32 " cbVisibleRect %" PRIu32 " num_rects %d",
517 numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
518
519 if (num_rects > 0)
520 {
521 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, ifman->input, num_rects, 16ull))
522 return ERROR_INVALID_DATA;
523
524 rects = (RECTANGLE_32*)calloc(num_rects, sizeof(RECTANGLE_32));
525 if (!rects)
526 return ERROR_OUTOFMEMORY;
527
528 for (size_t i = 0; i < num_rects; i++)
529 {
530 Stream_Read_UINT32(ifman->input, rects[i].top); /* Top */
531 Stream_Read_UINT32(ifman->input, rects[i].left); /* Left */
532 Stream_Read_UINT32(ifman->input, rects[i].height); /* Bottom */
533 Stream_Read_UINT32(ifman->input, rects[i].width); /* Right */
534 rects[i].width -= rects[i].left;
535 rects[i].height -= rects[i].top;
536 DEBUG_TSMF("rect %d: %" PRId16 " %" PRId16 " %" PRId16 " %" PRId16 "", i, rects[i].x,
537 rects[i].y, rects[i].width, rects[i].height);
538 }
539 }
540
541 const BOOL rc = tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height,
542 num_rects, rects);
543 free(rects);
544 if (!rc)
545 return ERROR_INVALID_OPERATION;
546
547 ifman->output_pending = TRUE;
548 return error;
549}
550
556UINT tsmf_ifman_set_allocator(TSMF_IFMAN* ifman)
557{
558 DEBUG_TSMF("");
559 ifman->output_pending = TRUE;
560 return CHANNEL_RC_OK;
561}
562
568UINT tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman)
569{
570 DEBUG_TSMF("");
571 tsmf_ifman_on_playback_paused(ifman);
572 ifman->output_pending = TRUE;
573 return CHANNEL_RC_OK;
574}
575
581UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
582{
583 TSMF_PRESENTATION* presentation = nullptr;
584 TSMF_STREAM* stream = nullptr;
585 UINT32 StreamId = 0;
586 UINT64 SampleStartTime = 0;
587 UINT64 SampleEndTime = 0;
588 UINT64 ThrottleDuration = 0;
589 UINT32 SampleExtensions = 0;
590 UINT32 cbData = 0;
591 UINT error = 0;
592
593 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 60))
594 return ERROR_INVALID_DATA;
595
596 Stream_Seek(ifman->input, 16);
597 Stream_Read_UINT32(ifman->input, StreamId);
598 Stream_Seek_UINT32(ifman->input); /* numSample */
599 Stream_Read_UINT64(ifman->input, SampleStartTime);
600 Stream_Read_UINT64(ifman->input, SampleEndTime);
601 Stream_Read_UINT64(ifman->input, ThrottleDuration);
602 Stream_Seek_UINT32(ifman->input); /* SampleFlags */
603 Stream_Read_UINT32(ifman->input, SampleExtensions);
604 Stream_Read_UINT32(ifman->input, cbData);
605
606 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, cbData))
607 return ERROR_INVALID_DATA;
608
609 DEBUG_TSMF("MessageId %" PRIu32 " StreamId %" PRIu32 " SampleStartTime %" PRIu64
610 " SampleEndTime %" PRIu64 " "
611 "ThrottleDuration %" PRIu64 " SampleExtensions %" PRIu32 " cbData %" PRIu32 "",
612 ifman->message_id, StreamId, SampleStartTime, SampleEndTime, ThrottleDuration,
613 SampleExtensions, cbData);
614 presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
615
616 if (!presentation)
617 {
618 WLog_ERR(TAG, "unknown presentation id");
619 return ERROR_NOT_FOUND;
620 }
621
622 stream = tsmf_stream_find_by_id(presentation, StreamId);
623
624 if (!stream)
625 {
626 WLog_ERR(TAG, "unknown stream id");
627 return ERROR_NOT_FOUND;
628 }
629
630 if (!tsmf_stream_push_sample(stream, ifman->channel_callback, ifman->message_id,
631 SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
632 cbData, Stream_Pointer(ifman->input)))
633 {
634 WLog_ERR(TAG, "unable to push sample");
635 return ERROR_OUTOFMEMORY;
636 }
637
638 if ((error = tsmf_presentation_sync(presentation)))
639 {
640 WLog_ERR(TAG, "tsmf_presentation_sync failed with error %" PRIu32 "", error);
641 return error;
642 }
643
644 ifman->output_pending = TRUE;
645 return CHANNEL_RC_OK;
646}
647
653UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
654{
655 UINT32 StreamId = 0;
656 TSMF_PRESENTATION* presentation = nullptr;
657 TSMF_STREAM* stream = nullptr;
658
659 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 20))
660 return ERROR_INVALID_DATA;
661
662 Stream_Seek(ifman->input, 16);
663 Stream_Read_UINT32(ifman->input, StreamId);
664 DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
665 presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
666
667 if (!presentation)
668 {
669 WLog_ERR(TAG, "unknown presentation id");
670 return ERROR_NOT_FOUND;
671 }
672
673 /* Flush message is for a stream, not the entire presentation
674 * therefore we only flush the stream as intended per the MS-RDPEV spec
675 */
676 stream = tsmf_stream_find_by_id(presentation, StreamId);
677
678 if (stream)
679 {
680 if (!tsmf_stream_flush(stream))
681 return ERROR_INVALID_OPERATION;
682 }
683 else
684 WLog_ERR(TAG, "unknown stream id");
685
686 ifman->output_pending = TRUE;
687 return CHANNEL_RC_OK;
688}
689
695UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
696{
697 UINT32 StreamId = 0;
698 TSMF_STREAM* stream = nullptr;
699 TSMF_PRESENTATION* presentation = nullptr;
700
701 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 20))
702 return ERROR_INVALID_DATA;
703
704 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
705 Stream_Seek(ifman->input, 16);
706 Stream_Read_UINT32(ifman->input, StreamId);
707
708 if (presentation)
709 {
710 stream = tsmf_stream_find_by_id(presentation, StreamId);
711
712 if (stream)
713 tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
714 }
715
716 DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
717 ifman->output_pending = TRUE;
718 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
719 return CHANNEL_RC_OK;
720}
721
727UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
728{
729 TSMF_PRESENTATION* presentation = nullptr;
730 DEBUG_TSMF("");
731
732 if (!Stream_CheckAndLogRequiredLength(TAG, ifman->input, 16))
733 return ERROR_INVALID_DATA;
734
735 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
736
737 if (presentation)
738 tsmf_presentation_start(presentation);
739 else
740 WLog_ERR(TAG, "unknown presentation id");
741
742 if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
743 return ERROR_OUTOFMEMORY;
744
745 Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
746 Stream_Write_UINT32(ifman->output, 0); /* StreamId */
747 Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
748 Stream_Write_UINT32(ifman->output, 0); /* cbData */
749 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
750 return CHANNEL_RC_OK;
751}
752
758UINT tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
759{
760 TSMF_PRESENTATION* presentation = nullptr;
761 DEBUG_TSMF("");
762 ifman->output_pending = TRUE;
763 /* Added pause control so gstreamer pipeline can be paused accordingly */
764 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
765
766 if (presentation)
767 {
768 if (!tsmf_presentation_paused(presentation))
769 return ERROR_INVALID_OPERATION;
770 }
771 else
772 WLog_ERR(TAG, "unknown presentation id");
773
774 return CHANNEL_RC_OK;
775}
776
782UINT tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
783{
784 TSMF_PRESENTATION* presentation = nullptr;
785 DEBUG_TSMF("");
786 ifman->output_pending = TRUE;
787 /* Added restart control so gstreamer pipeline can be resumed accordingly */
788 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
789
790 if (presentation)
791 {
792 if (!tsmf_presentation_restarted(presentation))
793 return ERROR_INVALID_OPERATION;
794 }
795 else
796 WLog_ERR(TAG, "unknown presentation id");
797
798 return CHANNEL_RC_OK;
799}
800
806UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
807{
808 TSMF_PRESENTATION* presentation = nullptr;
809 DEBUG_TSMF("");
810 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
811
812 if (presentation)
813 {
814 if (!tsmf_presentation_stop(presentation))
815 return ERROR_INVALID_OPERATION;
816 }
817 else
818 WLog_ERR(TAG, "unknown presentation id");
819
820 if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
821 return ERROR_OUTOFMEMORY;
822
823 Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
824 Stream_Write_UINT32(ifman->output, 0); /* StreamId */
825 Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */
826 Stream_Write_UINT32(ifman->output, 0); /* cbData */
827 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
828 return CHANNEL_RC_OK;
829}
830
836UINT tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman)
837{
838 DEBUG_TSMF("");
839
840 if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
841 return ERROR_OUTOFMEMORY;
842
843 Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
844 Stream_Write_UINT32(ifman->output, 0); /* StreamId */
845 Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_MONITORCHANGED); /* EventId */
846 Stream_Write_UINT32(ifman->output, 0); /* cbData */
847 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
848 return CHANNEL_RC_OK;
849}