1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Video Redirection Virtual Channel - Interface Manipulation
4 *
5 * Copyright 2010-2011 Vic Lee
6 * Copyright 2012 Hewlett-Packard Development Company, L.P.
7 * Copyright 2015 Thincast Technologies GmbH
8 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <winpr/crt.h>
32
33 #include <winpr/stream.h>
34
35 #include "tsmf_types.h"
36 #include "tsmf_constants.h"
37 #include "tsmf_media.h"
38 #include "tsmf_codec.h"
39
40 #include "tsmf_ifman.h"
41
42 /**
43 * Function description
44 *
45 * @return 0 on success, otherwise a Win32 error code
46 */
tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN * ifman)47 UINT tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
48 {
49 UINT32 CapabilityValue;
50
51 if (Stream_GetRemainingLength(ifman->input) < 4)
52 return ERROR_INVALID_DATA;
53
54 Stream_Read_UINT32(ifman->input, CapabilityValue);
55 DEBUG_TSMF("server CapabilityValue %" PRIu32 "", CapabilityValue);
56
57 if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
58 return ERROR_INVALID_DATA;
59
60 Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */
61 Stream_Write_UINT32(ifman->output, 0); /* Result */
62 return CHANNEL_RC_OK;
63 }
64
65 /**
66 * Function description
67 *
68 * @return 0 on success, otherwise a Win32 error code
69 */
tsmf_ifman_exchange_capability_request(TSMF_IFMAN * ifman)70 UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
71 {
72 UINT32 i;
73 UINT32 v;
74 UINT32 pos;
75 UINT32 CapabilityType;
76 UINT32 cbCapabilityLength;
77 UINT32 numHostCapabilities;
78
79 if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4))
80 return ERROR_OUTOFMEMORY;
81
82 pos = Stream_GetPosition(ifman->output);
83 Stream_Copy(ifman->input, ifman->output, ifman->input_size);
84 Stream_SetPosition(ifman->output, pos);
85
86 if (Stream_GetRemainingLength(ifman->output) < 4)
87 return ERROR_INVALID_DATA;
88
89 Stream_Read_UINT32(ifman->output, numHostCapabilities);
90
91 for (i = 0; i < numHostCapabilities; i++)
92 {
93 if (Stream_GetRemainingLength(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_GetRemainingLength(ifman->output) < cbCapabilityLength)
100 return ERROR_INVALID_DATA;
101
102 pos = Stream_GetPosition(ifman->output);
103
104 switch (CapabilityType)
105 {
106 case 1: /* Protocol version request */
107 if (Stream_GetRemainingLength(ifman->output) < 4)
108 return ERROR_INVALID_DATA;
109
110 Stream_Read_UINT32(ifman->output, v);
111 DEBUG_TSMF("server protocol version %" PRIu32 "", v);
112 break;
113
114 case 2: /* Supported platform */
115 if (Stream_GetRemainingLength(ifman->output) < 4)
116 return ERROR_INVALID_DATA;
117
118 Stream_Peek_UINT32(ifman->output, v);
119 DEBUG_TSMF("server supported platform %" PRIu32 "", v);
120 /* Claim that we support both MF and DShow platforms. */
121 Stream_Write_UINT32(ifman->output, MMREDIR_CAPABILITY_PLATFORM_MF |
122 MMREDIR_CAPABILITY_PLATFORM_DSHOW);
123 break;
124
125 default:
126 WLog_ERR(TAG, "skipping unknown capability type %" PRIu32 "", CapabilityType);
127 break;
128 }
129
130 Stream_SetPosition(ifman->output, pos + cbCapabilityLength);
131 }
132
133 Stream_Write_UINT32(ifman->output, 0); /* Result */
134 ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
135 return CHANNEL_RC_OK;
136 }
137
138 /**
139 * Function description
140 *
141 * @return 0 on success, otherwise a Win32 error code
142 */
tsmf_ifman_check_format_support_request(TSMF_IFMAN * ifman)143 UINT tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
144 {
145 UINT32 numMediaType;
146 UINT32 PlatformCookie;
147 UINT32 FormatSupported = 1;
148
149 if (Stream_GetRemainingLength(ifman->input) < 12)
150 return ERROR_INVALID_DATA;
151
152 Stream_Read_UINT32(ifman->input, PlatformCookie);
153 Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
154 Stream_Read_UINT32(ifman->input, numMediaType);
155 DEBUG_TSMF("PlatformCookie %" PRIu32 " numMediaType %" PRIu32 "", PlatformCookie, numMediaType);
156
157 if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input))
158 FormatSupported = 0;
159
160 if (FormatSupported)
161 DEBUG_TSMF("format ok.");
162
163 if (!Stream_EnsureRemainingCapacity(ifman->output, 12))
164 return -1;
165
166 Stream_Write_UINT32(ifman->output, FormatSupported);
167 Stream_Write_UINT32(ifman->output, PlatformCookie);
168 Stream_Write_UINT32(ifman->output, 0); /* Result */
169 ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
170 return CHANNEL_RC_OK;
171 }
172
173 /**
174 * Function description
175 *
176 * @return 0 on success, otherwise a Win32 error code
177 */
tsmf_ifman_on_new_presentation(TSMF_IFMAN * ifman)178 UINT tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
179 {
180 UINT status = CHANNEL_RC_OK;
181 TSMF_PRESENTATION* presentation;
182 DEBUG_TSMF("");
183
184 if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE)
185 return ERROR_INVALID_DATA;
186
187 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
188
189 if (presentation)
190 {
191 DEBUG_TSMF("Presentation already exists");
192 ifman->output_pending = FALSE;
193 return CHANNEL_RC_OK;
194 }
195
196 presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback);
197
198 if (!presentation)
199 status = ERROR_OUTOFMEMORY;
200 else
201 tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
202
203 ifman->output_pending = TRUE;
204 return status;
205 }
206
207 /**
208 * Function description
209 *
210 * @return 0 on success, otherwise a Win32 error code
211 */
tsmf_ifman_add_stream(TSMF_IFMAN * ifman,rdpContext * rdpcontext)212 UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
213 {
214 UINT32 StreamId;
215 UINT status = CHANNEL_RC_OK;
216 TSMF_STREAM* stream;
217 TSMF_PRESENTATION* presentation;
218 DEBUG_TSMF("");
219
220 if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
221 return ERROR_INVALID_DATA;
222
223 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
224 Stream_Seek(ifman->input, GUID_SIZE);
225
226 if (!presentation)
227 {
228 WLog_ERR(TAG, "unknown presentation id");
229 status = ERROR_NOT_FOUND;
230 }
231 else
232 {
233 Stream_Read_UINT32(ifman->input, StreamId);
234 Stream_Seek_UINT32(ifman->input); /* numMediaType */
235 stream = tsmf_stream_new(presentation, StreamId, rdpcontext);
236
237 if (!stream)
238 {
239 WLog_ERR(TAG, "failed to create stream");
240 return ERROR_OUTOFMEMORY;
241 }
242
243 if (!tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input))
244 {
245 WLog_ERR(TAG, "failed to set stream format");
246 return ERROR_OUTOFMEMORY;
247 }
248
249 tsmf_stream_start_threads(stream);
250 }
251
252 ifman->output_pending = TRUE;
253 return status;
254 }
255
256 /**
257 * Function description
258 *
259 * @return 0 on success, otherwise a Win32 error code
260 */
tsmf_ifman_set_topology_request(TSMF_IFMAN * ifman)261 UINT tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
262 {
263 DEBUG_TSMF("");
264
265 if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
266 return ERROR_OUTOFMEMORY;
267
268 Stream_Write_UINT32(ifman->output, 1); /* TopologyReady */
269 Stream_Write_UINT32(ifman->output, 0); /* Result */
270 ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
271 return CHANNEL_RC_OK;
272 }
273
274 /**
275 * Function description
276 *
277 * @return 0 on success, otherwise a Win32 error code
278 */
tsmf_ifman_remove_stream(TSMF_IFMAN * ifman)279 UINT tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
280 {
281 int status = CHANNEL_RC_OK;
282 UINT32 StreamId;
283 TSMF_STREAM* stream;
284 TSMF_PRESENTATION* presentation;
285 DEBUG_TSMF("");
286
287 if (Stream_GetRemainingLength(ifman->input) < 20)
288 return ERROR_INVALID_DATA;
289
290 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
291 Stream_Seek(ifman->input, GUID_SIZE);
292
293 if (!presentation)
294 {
295 status = ERROR_NOT_FOUND;
296 }
297 else
298 {
299 Stream_Read_UINT32(ifman->input, StreamId);
300 stream = tsmf_stream_find_by_id(presentation, StreamId);
301
302 if (stream)
303 tsmf_stream_free(stream);
304 else
305 status = ERROR_NOT_FOUND;
306 }
307
308 ifman->output_pending = TRUE;
309 return status;
310 }
311
tsmf_stream_read_float(wStream * s)312 static float tsmf_stream_read_float(wStream* s)
313 {
314 float fValue;
315 UINT32 iValue;
316 Stream_Read_UINT32(s, iValue);
317 CopyMemory(&fValue, &iValue, 4);
318 return fValue;
319 }
320
321 /**
322 * Function description
323 *
324 * @return 0 on success, otherwise a Win32 error code
325 */
tsmf_ifman_set_source_video_rect(TSMF_IFMAN * ifman)326 UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
327 {
328 UINT status = CHANNEL_RC_OK;
329 float Left, Top;
330 float Right, Bottom;
331 TSMF_PRESENTATION* presentation;
332 DEBUG_TSMF("");
333
334 if (Stream_GetRemainingLength(ifman->input) < 32)
335 return ERROR_INVALID_DATA;
336
337 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
338 Stream_Seek(ifman->input, GUID_SIZE);
339
340 if (!presentation)
341 {
342 status = ERROR_NOT_FOUND;
343 }
344 else
345 {
346 Left = tsmf_stream_read_float(ifman->input); /* Left (4 bytes) */
347 Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */
348 Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */
349 Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */
350 DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f", Left, Top, Right,
351 Bottom);
352 }
353
354 ifman->output_pending = TRUE;
355 return status;
356 }
357
358 /**
359 * Function description
360 *
361 * @return 0 on success, otherwise a Win32 error code
362 */
tsmf_ifman_shutdown_presentation(TSMF_IFMAN * ifman)363 UINT tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
364 {
365 TSMF_PRESENTATION* presentation;
366 DEBUG_TSMF("");
367
368 if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE)
369 return ERROR_INVALID_DATA;
370
371 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
372
373 if (presentation)
374 tsmf_presentation_free(presentation);
375 else
376 {
377 WLog_ERR(TAG, "unknown presentation id");
378 return ERROR_NOT_FOUND;
379 }
380
381 if (!Stream_EnsureRemainingCapacity(ifman->output, 4))
382 return ERROR_OUTOFMEMORY;
383
384 Stream_Write_UINT32(ifman->output, 0); /* Result */
385 ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
386 return CHANNEL_RC_OK;
387 }
388
389 /**
390 * Function description
391 *
392 * @return 0 on success, otherwise a Win32 error code
393 */
tsmf_ifman_on_stream_volume(TSMF_IFMAN * ifman)394 UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
395 {
396 TSMF_PRESENTATION* presentation;
397 UINT32 newVolume;
398 UINT32 muted;
399 DEBUG_TSMF("on stream volume");
400
401 if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
402 return ERROR_INVALID_DATA;
403
404 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
405
406 if (!presentation)
407 {
408 WLog_ERR(TAG, "unknown presentation id");
409 return ERROR_NOT_FOUND;
410 }
411
412 Stream_Seek(ifman->input, 16);
413 Stream_Read_UINT32(ifman->input, newVolume);
414 DEBUG_TSMF("on stream volume: new volume=[%" PRIu32 "]", newVolume);
415 Stream_Read_UINT32(ifman->input, muted);
416 DEBUG_TSMF("on stream volume: muted=[%" PRIu32 "]", muted);
417
418 if (!tsmf_presentation_volume_changed(presentation, newVolume, muted))
419 return ERROR_INVALID_OPERATION;
420
421 ifman->output_pending = TRUE;
422 return 0;
423 }
424
425 /**
426 * Function description
427 *
428 * @return 0 on success, otherwise a Win32 error code
429 */
tsmf_ifman_on_channel_volume(TSMF_IFMAN * ifman)430 UINT tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
431 {
432 TSMF_PRESENTATION* presentation;
433 DEBUG_TSMF("on channel volume");
434
435 if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
436 return ERROR_INVALID_DATA;
437
438 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
439
440 if (presentation)
441 {
442 UINT32 channelVolume;
443 UINT32 changedChannel;
444 Stream_Seek(ifman->input, 16);
445 Stream_Read_UINT32(ifman->input, channelVolume);
446 DEBUG_TSMF("on channel volume: channel volume=[%" PRIu32 "]", channelVolume);
447 Stream_Read_UINT32(ifman->input, changedChannel);
448 DEBUG_TSMF("on stream volume: changed channel=[%" PRIu32 "]", changedChannel);
449 }
450
451 ifman->output_pending = TRUE;
452 return CHANNEL_RC_OK;
453 }
454
455 /**
456 * Function description
457 *
458 * @return 0 on success, otherwise a Win32 error code
459 */
tsmf_ifman_set_video_window(TSMF_IFMAN * ifman)460 UINT tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
461 {
462 DEBUG_TSMF("");
463 ifman->output_pending = TRUE;
464 return CHANNEL_RC_OK;
465 }
466
467 /**
468 * Function description
469 *
470 * @return 0 on success, otherwise a Win32 error code
471 */
tsmf_ifman_update_geometry_info(TSMF_IFMAN * ifman)472 UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
473 {
474 TSMF_PRESENTATION* presentation;
475 UINT32 numGeometryInfo;
476 UINT32 Left;
477 UINT32 Top;
478 UINT32 Width;
479 UINT32 Height;
480 UINT32 cbVisibleRect;
481 RDP_RECT* rects = NULL;
482 int num_rects = 0;
483 UINT error = CHANNEL_RC_OK;
484 int i;
485 size_t pos;
486
487 if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 32)
488 return ERROR_INVALID_DATA;
489
490 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
491
492 if (!presentation)
493 return ERROR_NOT_FOUND;
494
495 Stream_Seek(ifman->input, 16);
496 Stream_Read_UINT32(ifman->input, numGeometryInfo);
497 pos = Stream_GetPosition(ifman->input);
498 Stream_Seek(ifman->input, 12); /* VideoWindowId (8 bytes), VideoWindowState (4 bytes) */
499 Stream_Read_UINT32(ifman->input, Width);
500 Stream_Read_UINT32(ifman->input, Height);
501 Stream_Read_UINT32(ifman->input, Left);
502 Stream_Read_UINT32(ifman->input, Top);
503 Stream_SetPosition(ifman->input, pos + numGeometryInfo);
504 Stream_Read_UINT32(ifman->input, cbVisibleRect);
505 num_rects = cbVisibleRect / 16;
506 DEBUG_TSMF("numGeometryInfo %" PRIu32 " Width %" PRIu32 " Height %" PRIu32 " Left %" PRIu32
507 " Top %" PRIu32 " cbVisibleRect %" PRIu32 " num_rects %d",
508 numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
509
510 if (num_rects > 0)
511 {
512 rects = (RDP_RECT*)calloc(num_rects, sizeof(RDP_RECT));
513
514 for (i = 0; i < num_rects; i++)
515 {
516 Stream_Read_UINT16(ifman->input, rects[i].y); /* Top */
517 Stream_Seek_UINT16(ifman->input);
518 Stream_Read_UINT16(ifman->input, rects[i].x); /* Left */
519 Stream_Seek_UINT16(ifman->input);
520 Stream_Read_UINT16(ifman->input, rects[i].height); /* Bottom */
521 Stream_Seek_UINT16(ifman->input);
522 Stream_Read_UINT16(ifman->input, rects[i].width); /* Right */
523 Stream_Seek_UINT16(ifman->input);
524 rects[i].width -= rects[i].x;
525 rects[i].height -= rects[i].y;
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 if (!tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects,
532 rects))
533 return ERROR_INVALID_OPERATION;
534
535 ifman->output_pending = TRUE;
536 return error;
537 }
538
539 /**
540 * Function description
541 *
542 * @return 0 on success, otherwise a Win32 error code
543 */
tsmf_ifman_set_allocator(TSMF_IFMAN * ifman)544 UINT tsmf_ifman_set_allocator(TSMF_IFMAN* ifman)
545 {
546 DEBUG_TSMF("");
547 ifman->output_pending = TRUE;
548 return CHANNEL_RC_OK;
549 }
550
551 /**
552 * Function description
553 *
554 * @return 0 on success, otherwise a Win32 error code
555 */
tsmf_ifman_notify_preroll(TSMF_IFMAN * ifman)556 UINT tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman)
557 {
558 DEBUG_TSMF("");
559 tsmf_ifman_on_playback_paused(ifman);
560 ifman->output_pending = TRUE;
561 return CHANNEL_RC_OK;
562 }
563
564 /**
565 * Function description
566 *
567 * @return 0 on success, otherwise a Win32 error code
568 */
tsmf_ifman_on_sample(TSMF_IFMAN * ifman)569 UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
570 {
571 TSMF_PRESENTATION* presentation;
572 TSMF_STREAM* stream;
573 UINT32 StreamId;
574 UINT64 SampleStartTime;
575 UINT64 SampleEndTime;
576 UINT64 ThrottleDuration;
577 UINT32 SampleExtensions;
578 UINT32 cbData;
579 UINT error;
580
581 if (Stream_GetRemainingLength(ifman->input) < 60)
582 return ERROR_INVALID_DATA;
583
584 Stream_Seek(ifman->input, 16);
585 Stream_Read_UINT32(ifman->input, StreamId);
586 Stream_Seek_UINT32(ifman->input); /* numSample */
587 Stream_Read_UINT64(ifman->input, SampleStartTime);
588 Stream_Read_UINT64(ifman->input, SampleEndTime);
589 Stream_Read_UINT64(ifman->input, ThrottleDuration);
590 Stream_Seek_UINT32(ifman->input); /* SampleFlags */
591 Stream_Read_UINT32(ifman->input, SampleExtensions);
592 Stream_Read_UINT32(ifman->input, cbData);
593
594 if (Stream_GetRemainingLength(ifman->input) < cbData)
595 return ERROR_INVALID_DATA;
596
597 DEBUG_TSMF("MessageId %" PRIu32 " StreamId %" PRIu32 " SampleStartTime %" PRIu64
598 " SampleEndTime %" PRIu64 " "
599 "ThrottleDuration %" PRIu64 " SampleExtensions %" PRIu32 " cbData %" PRIu32 "",
600 ifman->message_id, StreamId, SampleStartTime, SampleEndTime, ThrottleDuration,
601 SampleExtensions, cbData);
602 presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
603
604 if (!presentation)
605 {
606 WLog_ERR(TAG, "unknown presentation id");
607 return ERROR_NOT_FOUND;
608 }
609
610 stream = tsmf_stream_find_by_id(presentation, StreamId);
611
612 if (!stream)
613 {
614 WLog_ERR(TAG, "unknown stream id");
615 return ERROR_NOT_FOUND;
616 }
617
618 if (!tsmf_stream_push_sample(stream, ifman->channel_callback, ifman->message_id,
619 SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
620 cbData, Stream_Pointer(ifman->input)))
621 {
622 WLog_ERR(TAG, "unable to push sample");
623 return ERROR_OUTOFMEMORY;
624 }
625
626 if ((error = tsmf_presentation_sync(presentation)))
627 {
628 WLog_ERR(TAG, "tsmf_presentation_sync failed with error %" PRIu32 "", error);
629 return error;
630 }
631
632 ifman->output_pending = TRUE;
633 return CHANNEL_RC_OK;
634 }
635
636 /**
637 * Function description
638 *
639 * @return 0 on success, otherwise a Win32 error code
640 */
tsmf_ifman_on_flush(TSMF_IFMAN * ifman)641 UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
642 {
643 UINT32 StreamId;
644 TSMF_PRESENTATION* presentation;
645 TSMF_STREAM* stream;
646
647 if (Stream_GetRemainingLength(ifman->input) < 20)
648 return ERROR_INVALID_DATA;
649
650 Stream_Seek(ifman->input, 16);
651 Stream_Read_UINT32(ifman->input, StreamId);
652 DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
653 presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
654
655 if (!presentation)
656 {
657 WLog_ERR(TAG, "unknown presentation id");
658 return ERROR_NOT_FOUND;
659 }
660
661 /* Flush message is for a stream, not the entire presentation
662 * therefore we only flush the stream as intended per the MS-RDPEV spec
663 */
664 stream = tsmf_stream_find_by_id(presentation, StreamId);
665
666 if (stream)
667 {
668 if (!tsmf_stream_flush(stream))
669 return ERROR_INVALID_OPERATION;
670 }
671 else
672 WLog_ERR(TAG, "unknown stream id");
673
674 ifman->output_pending = TRUE;
675 return CHANNEL_RC_OK;
676 }
677
678 /**
679 * Function description
680 *
681 * @return 0 on success, otherwise a Win32 error code
682 */
tsmf_ifman_on_end_of_stream(TSMF_IFMAN * ifman)683 UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
684 {
685 UINT32 StreamId;
686 TSMF_STREAM* stream = NULL;
687 TSMF_PRESENTATION* presentation;
688
689 if (Stream_GetRemainingLength(ifman->input) < 20)
690 return ERROR_INVALID_DATA;
691
692 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
693 Stream_Seek(ifman->input, 16);
694 Stream_Read_UINT32(ifman->input, StreamId);
695
696 if (presentation)
697 {
698 stream = tsmf_stream_find_by_id(presentation, StreamId);
699
700 if (stream)
701 tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
702 }
703
704 DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
705 ifman->output_pending = TRUE;
706 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
707 return CHANNEL_RC_OK;
708 }
709
710 /**
711 * Function description
712 *
713 * @return 0 on success, otherwise a Win32 error code
714 */
tsmf_ifman_on_playback_started(TSMF_IFMAN * ifman)715 UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
716 {
717 TSMF_PRESENTATION* presentation;
718 DEBUG_TSMF("");
719
720 if (Stream_GetRemainingLength(ifman->input) < 16)
721 return ERROR_INVALID_DATA;
722
723 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
724
725 if (presentation)
726 tsmf_presentation_start(presentation);
727 else
728 WLog_ERR(TAG, "unknown presentation id");
729
730 if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
731 return ERROR_OUTOFMEMORY;
732
733 Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
734 Stream_Write_UINT32(ifman->output, 0); /* StreamId */
735 Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
736 Stream_Write_UINT32(ifman->output, 0); /* cbData */
737 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
738 return CHANNEL_RC_OK;
739 }
740
741 /**
742 * Function description
743 *
744 * @return 0 on success, otherwise a Win32 error code
745 */
tsmf_ifman_on_playback_paused(TSMF_IFMAN * ifman)746 UINT tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
747 {
748 TSMF_PRESENTATION* presentation;
749 DEBUG_TSMF("");
750 ifman->output_pending = TRUE;
751 /* Added pause control so gstreamer pipeline can be paused accordingly */
752 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
753
754 if (presentation)
755 {
756 if (!tsmf_presentation_paused(presentation))
757 return ERROR_INVALID_OPERATION;
758 }
759 else
760 WLog_ERR(TAG, "unknown presentation id");
761
762 return CHANNEL_RC_OK;
763 }
764
765 /**
766 * Function description
767 *
768 * @return 0 on success, otherwise a Win32 error code
769 */
tsmf_ifman_on_playback_restarted(TSMF_IFMAN * ifman)770 UINT tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
771 {
772 TSMF_PRESENTATION* presentation;
773 DEBUG_TSMF("");
774 ifman->output_pending = TRUE;
775 /* Added restart control so gstreamer pipeline can be resumed accordingly */
776 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
777
778 if (presentation)
779 {
780 if (!tsmf_presentation_restarted(presentation))
781 return ERROR_INVALID_OPERATION;
782 }
783 else
784 WLog_ERR(TAG, "unknown presentation id");
785
786 return CHANNEL_RC_OK;
787 }
788
789 /**
790 * Function description
791 *
792 * @return 0 on success, otherwise a Win32 error code
793 */
tsmf_ifman_on_playback_stopped(TSMF_IFMAN * ifman)794 UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
795 {
796 TSMF_PRESENTATION* presentation;
797 DEBUG_TSMF("");
798 presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
799
800 if (presentation)
801 {
802 if (!tsmf_presentation_stop(presentation))
803 return ERROR_INVALID_OPERATION;
804 }
805 else
806 WLog_ERR(TAG, "unknown presentation id");
807
808 if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
809 return ERROR_OUTOFMEMORY;
810
811 Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
812 Stream_Write_UINT32(ifman->output, 0); /* StreamId */
813 Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */
814 Stream_Write_UINT32(ifman->output, 0); /* cbData */
815 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
816 return CHANNEL_RC_OK;
817 }
818
819 /**
820 * Function description
821 *
822 * @return 0 on success, otherwise a Win32 error code
823 */
tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN * ifman)824 UINT tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman)
825 {
826 DEBUG_TSMF("");
827
828 if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
829 return ERROR_OUTOFMEMORY;
830
831 Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
832 Stream_Write_UINT32(ifman->output, 0); /* StreamId */
833 Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_MONITORCHANGED); /* EventId */
834 Stream_Write_UINT32(ifman->output, 0); /* cbData */
835 ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
836 return CHANNEL_RC_OK;
837 }
838