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