Blame channels/tsmf/client/tsmf_ifman.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Video Redirection Virtual Channel - Interface Manipulation
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2010-2011 Vic Lee
Packit 1fb8d4
 * Copyright 2012 Hewlett-Packard Development Company, L.P.
Packit 1fb8d4
 * Copyright 2015 Thincast Technologies GmbH
Packit 1fb8d4
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/stream.h>
Packit 1fb8d4
Packit 1fb8d4
#include "tsmf_types.h"
Packit 1fb8d4
#include "tsmf_constants.h"
Packit 1fb8d4
#include "tsmf_media.h"
Packit 1fb8d4
#include "tsmf_codec.h"
Packit 1fb8d4
Packit 1fb8d4
#include "tsmf_ifman.h"
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 CapabilityValue;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < 4)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, CapabilityValue);
Packit Service 5a9772
	DEBUG_TSMF("server CapabilityValue %" PRIu32 "", CapabilityValue);
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, 0); /* Result */
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i;
Packit 1fb8d4
	UINT32 v;
Packit 1fb8d4
	UINT32 pos;
Packit 1fb8d4
	UINT32 CapabilityType;
Packit 1fb8d4
	UINT32 cbCapabilityLength;
Packit 1fb8d4
	UINT32 numHostCapabilities;
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4))
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
Packit 1fb8d4
	pos = Stream_GetPosition(ifman->output);
Packit 1fb8d4
	Stream_Copy(ifman->input, ifman->output, ifman->input_size);
Packit 1fb8d4
	Stream_SetPosition(ifman->output, pos);
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->output) < 4)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(ifman->output, numHostCapabilities);
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < numHostCapabilities; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (Stream_GetRemainingLength(ifman->output) < 8)
Packit 1fb8d4
			return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Read_UINT32(ifman->output, CapabilityType);
Packit 1fb8d4
		Stream_Read_UINT32(ifman->output, cbCapabilityLength);
Packit 1fb8d4
Packit 1fb8d4
		if (Stream_GetRemainingLength(ifman->output) < cbCapabilityLength)
Packit 1fb8d4
			return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
		pos = Stream_GetPosition(ifman->output);
Packit 1fb8d4
Packit 1fb8d4
		switch (CapabilityType)
Packit 1fb8d4
		{
Packit 1fb8d4
			case 1: /* Protocol version request */
Packit 1fb8d4
				if (Stream_GetRemainingLength(ifman->output) < 4)
Packit 1fb8d4
					return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
				Stream_Read_UINT32(ifman->output, v);
Packit Service 5a9772
				DEBUG_TSMF("server protocol version %" PRIu32 "", v);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case 2: /* Supported platform */
Packit 1fb8d4
				if (Stream_GetRemainingLength(ifman->output) < 4)
Packit 1fb8d4
					return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
				Stream_Peek_UINT32(ifman->output, v);
Packit Service 5a9772
				DEBUG_TSMF("server supported platform %" PRIu32 "", v);
Packit 1fb8d4
				/* Claim that we support both MF and DShow platforms. */
Packit Service 5a9772
				Stream_Write_UINT32(ifman->output, MMREDIR_CAPABILITY_PLATFORM_MF |
Packit Service 5a9772
				                                       MMREDIR_CAPABILITY_PLATFORM_DSHOW);
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit Service 5a9772
				WLog_ERR(TAG, "skipping unknown capability type %" PRIu32 "", CapabilityType);
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		Stream_SetPosition(ifman->output, pos + cbCapabilityLength);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, 0); /* Result */
Packit 1fb8d4
	ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 numMediaType;
Packit 1fb8d4
	UINT32 PlatformCookie;
Packit 1fb8d4
	UINT32 FormatSupported = 1;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < 12)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, PlatformCookie);
Packit 1fb8d4
	Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, numMediaType);
Packit Service 5a9772
	DEBUG_TSMF("PlatformCookie %" PRIu32 " numMediaType %" PRIu32 "", PlatformCookie, numMediaType);
Packit 1fb8d4
Packit 1fb8d4
	if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input))
Packit 1fb8d4
		FormatSupported = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (FormatSupported)
Packit 1fb8d4
		DEBUG_TSMF("format ok.");
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(ifman->output, 12))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, FormatSupported);
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, PlatformCookie);
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, 0); /* Result */
Packit 1fb8d4
	ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT status = CHANNEL_RC_OK;
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
Packit 1fb8d4
	if (presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		DEBUG_TSMF("Presentation already exists");
Packit 1fb8d4
		ifman->output_pending = FALSE;
Packit 1fb8d4
		return CHANNEL_RC_OK;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback);
Packit 1fb8d4
Packit 1fb8d4
	if (!presentation)
Packit 1fb8d4
		status = ERROR_OUTOFMEMORY;
Packit 1fb8d4
	else
Packit 1fb8d4
		tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
Packit 1fb8d4
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 StreamId;
Packit 1fb8d4
	UINT status = CHANNEL_RC_OK;
Packit 1fb8d4
	TSMF_STREAM* stream;
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
	Stream_Seek(ifman->input, GUID_SIZE);
Packit 1fb8d4
Packit 1fb8d4
	if (!presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unknown presentation id");
Packit 1fb8d4
		status = ERROR_NOT_FOUND;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Read_UINT32(ifman->input, StreamId);
Packit 1fb8d4
		Stream_Seek_UINT32(ifman->input); /* numMediaType */
Packit 1fb8d4
		stream = tsmf_stream_new(presentation, StreamId, rdpcontext);
Packit 1fb8d4
Packit 1fb8d4
		if (!stream)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "failed to create stream");
Packit 1fb8d4
			return ERROR_OUTOFMEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "failed to set stream format");
Packit 1fb8d4
			return ERROR_OUTOFMEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		tsmf_stream_start_threads(stream);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, 1); /* TopologyReady */
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, 0); /* Result */
Packit 1fb8d4
	ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = CHANNEL_RC_OK;
Packit 1fb8d4
	UINT32 StreamId;
Packit 1fb8d4
	TSMF_STREAM* stream;
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < 20)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
	Stream_Seek(ifman->input, GUID_SIZE);
Packit 1fb8d4
Packit 1fb8d4
	if (!presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		status = ERROR_NOT_FOUND;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_Read_UINT32(ifman->input, StreamId);
Packit 1fb8d4
		stream = tsmf_stream_find_by_id(presentation, StreamId);
Packit 1fb8d4
Packit 1fb8d4
		if (stream)
Packit 1fb8d4
			tsmf_stream_free(stream);
Packit 1fb8d4
		else
Packit 1fb8d4
			status = ERROR_NOT_FOUND;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static float tsmf_stream_read_float(wStream* s)
Packit 1fb8d4
{
Packit 1fb8d4
	float fValue;
Packit 1fb8d4
	UINT32 iValue;
Packit 1fb8d4
	Stream_Read_UINT32(s, iValue);
Packit 1fb8d4
	CopyMemory(&fValue, &iValue, 4);
Packit 1fb8d4
	return fValue;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT status = CHANNEL_RC_OK;
Packit 1fb8d4
	float Left, Top;
Packit 1fb8d4
	float Right, Bottom;
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < 32)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
	Stream_Seek(ifman->input, GUID_SIZE);
Packit 1fb8d4
Packit 1fb8d4
	if (!presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		status = ERROR_NOT_FOUND;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit Service 5a9772
		Left = tsmf_stream_read_float(ifman->input);   /* Left (4 bytes) */
Packit Service 5a9772
		Top = tsmf_stream_read_float(ifman->input);    /* Top (4 bytes) */
Packit Service 5a9772
		Right = tsmf_stream_read_float(ifman->input);  /* Right (4 bytes) */
Packit 1fb8d4
		Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */
Packit Service 5a9772
		DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f", Left, Top, Right,
Packit Service 5a9772
		           Bottom);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
Packit 1fb8d4
	if (presentation)
Packit 1fb8d4
		tsmf_presentation_free(presentation);
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unknown presentation id");
Packit 1fb8d4
		return ERROR_NOT_FOUND;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(ifman->output, 4))
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, 0); /* Result */
Packit 1fb8d4
	ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	UINT32 newVolume;
Packit 1fb8d4
	UINT32 muted;
Packit 1fb8d4
	DEBUG_TSMF("on stream volume");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
Packit 1fb8d4
	if (!presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unknown presentation id");
Packit 1fb8d4
		return ERROR_NOT_FOUND;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(ifman->input, 16);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, newVolume);
Packit Service 5a9772
	DEBUG_TSMF("on stream volume: new volume=[%" PRIu32 "]", newVolume);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, muted);
Packit Service 5a9772
	DEBUG_TSMF("on stream volume: muted=[%" PRIu32 "]", muted);
Packit 1fb8d4
Packit 1fb8d4
	if (!tsmf_presentation_volume_changed(presentation, newVolume, muted))
Packit 1fb8d4
		return ERROR_INVALID_OPERATION;
Packit 1fb8d4
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("on channel volume");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
Packit 1fb8d4
	if (presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 channelVolume;
Packit 1fb8d4
		UINT32 changedChannel;
Packit 1fb8d4
		Stream_Seek(ifman->input, 16);
Packit 1fb8d4
		Stream_Read_UINT32(ifman->input, channelVolume);
Packit Service 5a9772
		DEBUG_TSMF("on channel volume: channel volume=[%" PRIu32 "]", channelVolume);
Packit 1fb8d4
		Stream_Read_UINT32(ifman->input, changedChannel);
Packit Service 5a9772
		DEBUG_TSMF("on stream volume: changed channel=[%" PRIu32 "]", changedChannel);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	UINT32 numGeometryInfo;
Packit 1fb8d4
	UINT32 Left;
Packit 1fb8d4
	UINT32 Top;
Packit 1fb8d4
	UINT32 Width;
Packit 1fb8d4
	UINT32 Height;
Packit 1fb8d4
	UINT32 cbVisibleRect;
Packit 1fb8d4
	RDP_RECT* rects = NULL;
Packit 1fb8d4
	int num_rects = 0;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	int i;
Packit 1fb8d4
	size_t pos;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 32)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
Packit 1fb8d4
	if (!presentation)
Packit 1fb8d4
		return ERROR_NOT_FOUND;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(ifman->input, 16);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, numGeometryInfo);
Packit 1fb8d4
	pos = Stream_GetPosition(ifman->input);
Packit 1fb8d4
	Stream_Seek(ifman->input, 12); /* VideoWindowId (8 bytes), VideoWindowState (4 bytes) */
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, Width);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, Height);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, Left);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, Top);
Packit 1fb8d4
	Stream_SetPosition(ifman->input, pos + numGeometryInfo);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, cbVisibleRect);
Packit 1fb8d4
	num_rects = cbVisibleRect / 16;
Packit Service 5a9772
	DEBUG_TSMF("numGeometryInfo %" PRIu32 " Width %" PRIu32 " Height %" PRIu32 " Left %" PRIu32
Packit Service 5a9772
	           " Top %" PRIu32 " cbVisibleRect %" PRIu32 " num_rects %d",
Packit 1fb8d4
	           numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
Packit 1fb8d4
Packit 1fb8d4
	if (num_rects > 0)
Packit 1fb8d4
	{
Packit Service 5a9772
		rects = (RDP_RECT*)calloc(num_rects, sizeof(RDP_RECT));
Packit 1fb8d4
Packit 1fb8d4
		for (i = 0; i < num_rects; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			Stream_Read_UINT16(ifman->input, rects[i].y); /* Top */
Packit 1fb8d4
			Stream_Seek_UINT16(ifman->input);
Packit 1fb8d4
			Stream_Read_UINT16(ifman->input, rects[i].x); /* Left */
Packit 1fb8d4
			Stream_Seek_UINT16(ifman->input);
Packit 1fb8d4
			Stream_Read_UINT16(ifman->input, rects[i].height); /* Bottom */
Packit 1fb8d4
			Stream_Seek_UINT16(ifman->input);
Packit 1fb8d4
			Stream_Read_UINT16(ifman->input, rects[i].width); /* Right */
Packit 1fb8d4
			Stream_Seek_UINT16(ifman->input);
Packit 1fb8d4
			rects[i].width -= rects[i].x;
Packit 1fb8d4
			rects[i].height -= rects[i].y;
Packit Service 5a9772
			DEBUG_TSMF("rect %d: %" PRId16 " %" PRId16 " %" PRId16 " %" PRId16 "", i, rects[i].x,
Packit Service 5a9772
			           rects[i].y, rects[i].width, rects[i].height);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (!tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects,
Packit Service 5a9772
	                                         rects))
Packit 1fb8d4
		return ERROR_INVALID_OPERATION;
Packit 1fb8d4
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return error;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_set_allocator(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
	tsmf_ifman_on_playback_paused(ifman);
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	TSMF_STREAM* stream;
Packit 1fb8d4
	UINT32 StreamId;
Packit 1fb8d4
	UINT64 SampleStartTime;
Packit 1fb8d4
	UINT64 SampleEndTime;
Packit 1fb8d4
	UINT64 ThrottleDuration;
Packit 1fb8d4
	UINT32 SampleExtensions;
Packit 1fb8d4
	UINT32 cbData;
Packit 1fb8d4
	UINT error;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < 60)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(ifman->input, 16);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, StreamId);
Packit 1fb8d4
	Stream_Seek_UINT32(ifman->input); /* numSample */
Packit 1fb8d4
	Stream_Read_UINT64(ifman->input, SampleStartTime);
Packit 1fb8d4
	Stream_Read_UINT64(ifman->input, SampleEndTime);
Packit 1fb8d4
	Stream_Read_UINT64(ifman->input, ThrottleDuration);
Packit 1fb8d4
	Stream_Seek_UINT32(ifman->input); /* SampleFlags */
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, SampleExtensions);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, cbData);
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < cbData)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit Service 5a9772
	DEBUG_TSMF("MessageId %" PRIu32 " StreamId %" PRIu32 " SampleStartTime %" PRIu64
Packit Service 5a9772
	           " SampleEndTime %" PRIu64 " "
Packit Service 5a9772
	           "ThrottleDuration %" PRIu64 " SampleExtensions %" PRIu32 " cbData %" PRIu32 "",
Packit Service 5a9772
	           ifman->message_id, StreamId, SampleStartTime, SampleEndTime, ThrottleDuration,
Packit Service 5a9772
	           SampleExtensions, cbData);
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
Packit 1fb8d4
Packit 1fb8d4
	if (!presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unknown presentation id");
Packit 1fb8d4
		return ERROR_NOT_FOUND;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	stream = tsmf_stream_find_by_id(presentation, StreamId);
Packit 1fb8d4
Packit 1fb8d4
	if (!stream)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unknown stream id");
Packit 1fb8d4
		return ERROR_NOT_FOUND;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (!tsmf_stream_push_sample(stream, ifman->channel_callback, ifman->message_id,
Packit Service 5a9772
	                             SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
Packit Service 5a9772
	                             cbData, Stream_Pointer(ifman->input)))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unable to push sample");
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((error = tsmf_presentation_sync(presentation)))
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "tsmf_presentation_sync failed with error %" PRIu32 "", error);
Packit 1fb8d4
		return error;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 StreamId;
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	TSMF_STREAM* stream;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < 20)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(ifman->input, 16);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, StreamId);
Packit Service 5a9772
	DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
Packit 1fb8d4
Packit 1fb8d4
	if (!presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unknown presentation id");
Packit 1fb8d4
		return ERROR_NOT_FOUND;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Flush message is for a stream, not the entire presentation
Packit 1fb8d4
	 * therefore we only flush the stream as intended per the MS-RDPEV spec
Packit 1fb8d4
	 */
Packit 1fb8d4
	stream = tsmf_stream_find_by_id(presentation, StreamId);
Packit 1fb8d4
Packit 1fb8d4
	if (stream)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!tsmf_stream_flush(stream))
Packit 1fb8d4
			return ERROR_INVALID_OPERATION;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
		WLog_ERR(TAG, "unknown stream id");
Packit 1fb8d4
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 StreamId;
Packit 1fb8d4
	TSMF_STREAM* stream = NULL;
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < 20)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
	Stream_Seek(ifman->input, 16);
Packit 1fb8d4
	Stream_Read_UINT32(ifman->input, StreamId);
Packit 1fb8d4
Packit 1fb8d4
	if (presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		stream = tsmf_stream_find_by_id(presentation, StreamId);
Packit 1fb8d4
Packit 1fb8d4
		if (stream)
Packit 1fb8d4
			tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	DEBUG_TSMF("StreamId %" PRIu32 "", StreamId);
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(ifman->input) < 16)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
Packit 1fb8d4
	if (presentation)
Packit 1fb8d4
		tsmf_presentation_start(presentation);
Packit 1fb8d4
	else
Packit 1fb8d4
		WLog_ERR(TAG, "unknown presentation id");
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION);         /* FunctionId */
Packit Service 5a9772
	Stream_Write_UINT32(ifman->output, 0);                                 /* StreamId */
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
Packit Service 5a9772
	Stream_Write_UINT32(ifman->output, 0);                                 /* cbData */
Packit 1fb8d4
	ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	/* Added pause control so gstreamer pipeline can be paused accordingly */
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
Packit 1fb8d4
	if (presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!tsmf_presentation_paused(presentation))
Packit 1fb8d4
			return ERROR_INVALID_OPERATION;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
		WLog_ERR(TAG, "unknown presentation id");
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
	ifman->output_pending = TRUE;
Packit 1fb8d4
	/* Added restart control so gstreamer pipeline can be resumed accordingly */
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
Packit 1fb8d4
	if (presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!tsmf_presentation_restarted(presentation))
Packit 1fb8d4
			return ERROR_INVALID_OPERATION;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
		WLog_ERR(TAG, "unknown presentation id");
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
	presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Packit 1fb8d4
Packit 1fb8d4
	if (presentation)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!tsmf_presentation_stop(presentation))
Packit 1fb8d4
			return ERROR_INVALID_OPERATION;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
		WLog_ERR(TAG, "unknown presentation id");
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION);        /* FunctionId */
Packit Service 5a9772
	Stream_Write_UINT32(ifman->output, 0);                                /* StreamId */
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */
Packit Service 5a9772
	Stream_Write_UINT32(ifman->output, 0);                                /* cbData */
Packit 1fb8d4
	ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Function description
Packit 1fb8d4
 *
Packit 1fb8d4
 * @return 0 on success, otherwise a Win32 error code
Packit 1fb8d4
 */
Packit 1fb8d4
UINT tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman)
Packit 1fb8d4
{
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
Packit Service 5a9772
	Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION);        /* FunctionId */
Packit Service 5a9772
	Stream_Write_UINT32(ifman->output, 0);                                /* StreamId */
Packit 1fb8d4
	Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_MONITORCHANGED); /* EventId */
Packit Service 5a9772
	Stream_Write_UINT32(ifman->output, 0);                                /* cbData */
Packit 1fb8d4
	ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}