Blame channels/tsmf/client/tsmf_main.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Video Redirection Virtual Channel
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2010-2011 Vic Lee
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 <winpr/crt.h>
Packit 1fb8d4
#include <winpr/stream.h>
Packit 1fb8d4
#include <winpr/cmdline.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/client/tsmf.h>
Packit 1fb8d4
Packit 1fb8d4
#include "tsmf_types.h"
Packit 1fb8d4
#include "tsmf_constants.h"
Packit 1fb8d4
#include "tsmf_ifman.h"
Packit 1fb8d4
#include "tsmf_media.h"
Packit 1fb8d4
Packit 1fb8d4
#include "tsmf_main.h"
Packit 1fb8d4
Packit 1fb8d4
BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s = NULL;
Packit 1fb8d4
	int status = -1;
Packit Service 5a9772
	TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback;
Packit 1fb8d4
Packit 1fb8d4
	if (!callback)
Packit 1fb8d4
	{
Packit 1fb8d4
		DEBUG_TSMF("No callback reference - unable to send eos response!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (callback && callback->stream_id && callback->channel && callback->channel->Write)
Packit 1fb8d4
	{
Packit 1fb8d4
		s = Stream_New(NULL, 24);
Packit 1fb8d4
Packit 1fb8d4
		if (!s)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY);
Packit 1fb8d4
		Stream_Write_UINT32(s, message_id);
Packit Service 5a9772
		Stream_Write_UINT32(s, CLIENT_EVENT_NOTIFICATION);     /* FunctionId */
Packit Service 5a9772
		Stream_Write_UINT32(s, callback->stream_id);           /* StreamId */
Packit 1fb8d4
		Stream_Write_UINT32(s, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */
Packit Service 5a9772
		Stream_Write_UINT32(s, 0);                             /* cbData */
Packit Service 5a9772
		DEBUG_TSMF("EOS response size %" PRIuz "", Stream_GetPosition(s));
Packit Service 5a9772
		status = callback->channel->Write(callback->channel, Stream_GetPosition(s),
Packit Service 5a9772
		                                  Stream_Buffer(s), NULL);
Packit 1fb8d4
Packit 1fb8d4
		if (status)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "response error %d", status);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		Stream_Free(s, TRUE);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (status == 0);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id,
Packit Service 5a9772
                       UINT64 duration, UINT32 data_size)
Packit 1fb8d4
{
Packit 1fb8d4
	wStream* s = NULL;
Packit 1fb8d4
	int status = -1;
Packit Service 5a9772
	TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback;
Packit 1fb8d4
Packit 1fb8d4
	if (!callback)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	s = Stream_New(NULL, 32);
Packit 1fb8d4
Packit 1fb8d4
	if (!s)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY);
Packit 1fb8d4
	Stream_Write_UINT32(s, message_id);
Packit Service 5a9772
	Stream_Write_UINT32(s, PLAYBACK_ACK);        /* FunctionId */
Packit 1fb8d4
	Stream_Write_UINT32(s, callback->stream_id); /* StreamId */
Packit Service 5a9772
	Stream_Write_UINT64(s, duration);            /* DataDuration */
Packit Service 5a9772
	Stream_Write_UINT64(s, data_size);           /* cbData */
Packit Service 5a9772
	DEBUG_TSMF("ACK response size %" PRIuz "", Stream_GetPosition(s));
Packit 1fb8d4
Packit 1fb8d4
	if (!callback->channel || !callback->channel->Write)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "callback=%p, channel=%p, write=%p", callback,
Packit 1fb8d4
		         (callback ? callback->channel : NULL),
Packit 1fb8d4
		         (callback && callback->channel ? callback->channel->Write : NULL));
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit Service 5a9772
		status = callback->channel->Write(callback->channel, Stream_GetPosition(s),
Packit Service 5a9772
		                                  Stream_Buffer(s), NULL);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (status)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "response error %d", status);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_Free(s, TRUE);
Packit 1fb8d4
	return (status == 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
static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
Packit 1fb8d4
{
Packit 1fb8d4
	size_t length;
Packit 1fb8d4
	wStream* input;
Packit 1fb8d4
	wStream* output;
Packit 1fb8d4
	UINT error = CHANNEL_RC_OK;
Packit 1fb8d4
	BOOL processed = FALSE;
Packit 1fb8d4
	TSMF_IFMAN ifman;
Packit 1fb8d4
	UINT32 MessageId;
Packit 1fb8d4
	UINT32 FunctionId;
Packit 1fb8d4
	UINT32 InterfaceId;
Packit Service 5a9772
	TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback;
Packit 1fb8d4
	UINT32 cbSize = Stream_GetRemainingLength(data);
Packit 1fb8d4
Packit 1fb8d4
	/* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */
Packit 1fb8d4
	if (cbSize < 12)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "invalid size. cbSize=%" PRIu32 "", cbSize);
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	input = data;
Packit 1fb8d4
	output = Stream_New(NULL, 256);
Packit 1fb8d4
Packit 1fb8d4
	if (!output)
Packit 1fb8d4
		return ERROR_OUTOFMEMORY;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Seek(output, 8);
Packit 1fb8d4
	Stream_Read_UINT32(input, InterfaceId); /* InterfaceId (4 bytes) */
Packit Service 5a9772
	Stream_Read_UINT32(input, MessageId);   /* MessageId (4 bytes) */
Packit Service 5a9772
	Stream_Read_UINT32(input, FunctionId);  /* FunctionId (4 bytes) */
Packit Service 5a9772
	DEBUG_TSMF("cbSize=%" PRIu32 " InterfaceId=0x%" PRIX32 " MessageId=0x%" PRIX32
Packit Service 5a9772
	           " FunctionId=0x%" PRIX32 "",
Packit 1fb8d4
	           cbSize, InterfaceId, MessageId, FunctionId);
Packit 1fb8d4
	ZeroMemory(&ifman, sizeof(TSMF_IFMAN));
Packit 1fb8d4
	ifman.channel_callback = pChannelCallback;
Packit Service 5a9772
	ifman.decoder_name = ((TSMF_PLUGIN*)callback->plugin)->decoder_name;
Packit Service 5a9772
	ifman.audio_name = ((TSMF_PLUGIN*)callback->plugin)->audio_name;
Packit Service 5a9772
	ifman.audio_device = ((TSMF_PLUGIN*)callback->plugin)->audio_device;
Packit 1fb8d4
	CopyMemory(ifman.presentation_id, callback->presentation_id, GUID_SIZE);
Packit 1fb8d4
	ifman.stream_id = callback->stream_id;
Packit 1fb8d4
	ifman.message_id = MessageId;
Packit 1fb8d4
	ifman.input = input;
Packit 1fb8d4
	ifman.input_size = cbSize - 12;
Packit 1fb8d4
	ifman.output = output;
Packit 1fb8d4
	ifman.output_pending = FALSE;
Packit 1fb8d4
	ifman.output_interface_id = InterfaceId;
Packit 1fb8d4
Packit Service 5a9772
	// fprintf(stderr, "InterfaceId: 0x%08"PRIX32" MessageId: 0x%08"PRIX32" FunctionId:
Packit Service 5a9772
	// 0x%08"PRIX32"\n", InterfaceId, MessageId, FunctionId);
Packit 1fb8d4
Packit 1fb8d4
	switch (InterfaceId)
Packit 1fb8d4
	{
Packit 1fb8d4
		case TSMF_INTERFACE_CAPABILITIES | STREAM_ID_NONE:
Packit 1fb8d4
			switch (FunctionId)
Packit 1fb8d4
			{
Packit 1fb8d4
				case RIM_EXCHANGE_CAPABILITY_REQUEST:
Packit 1fb8d4
					error = tsmf_ifman_rim_exchange_capability_request(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case RIMCALL_RELEASE:
Packit 1fb8d4
				case RIMCALL_QUERYINTERFACE:
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				default:
Packit 1fb8d4
					break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case TSMF_INTERFACE_DEFAULT | STREAM_ID_PROXY:
Packit 1fb8d4
			switch (FunctionId)
Packit 1fb8d4
			{
Packit 1fb8d4
				case SET_CHANNEL_PARAMS:
Packit 1fb8d4
					if (Stream_GetRemainingLength(input) < GUID_SIZE + 4)
Packit 1fb8d4
					{
Packit 1fb8d4
						error = ERROR_INVALID_DATA;
Packit 1fb8d4
						goto out;
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					CopyMemory(callback->presentation_id, Stream_Pointer(input), GUID_SIZE);
Packit 1fb8d4
					Stream_Seek(input, GUID_SIZE);
Packit 1fb8d4
					Stream_Read_UINT32(input, callback->stream_id);
Packit Service 5a9772
					DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%" PRIu32 "", callback->stream_id);
Packit 1fb8d4
					ifman.output_pending = TRUE;
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case EXCHANGE_CAPABILITIES_REQ:
Packit 1fb8d4
					error = tsmf_ifman_exchange_capability_request(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case CHECK_FORMAT_SUPPORT_REQ:
Packit 1fb8d4
					error = tsmf_ifman_check_format_support_request(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_NEW_PRESENTATION:
Packit 1fb8d4
					error = tsmf_ifman_on_new_presentation(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ADD_STREAM:
Packit Service 5a9772
					error =
Packit Service 5a9772
					    tsmf_ifman_add_stream(&ifman, ((TSMF_PLUGIN*)callback->plugin)->rdpcontext);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case SET_TOPOLOGY_REQ:
Packit 1fb8d4
					error = tsmf_ifman_set_topology_request(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case REMOVE_STREAM:
Packit 1fb8d4
					error = tsmf_ifman_remove_stream(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case SET_SOURCE_VIDEO_RECT:
Packit 1fb8d4
					error = tsmf_ifman_set_source_video_rect(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case SHUTDOWN_PRESENTATION_REQ:
Packit 1fb8d4
					error = tsmf_ifman_shutdown_presentation(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_STREAM_VOLUME:
Packit 1fb8d4
					error = tsmf_ifman_on_stream_volume(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_CHANNEL_VOLUME:
Packit 1fb8d4
					error = tsmf_ifman_on_channel_volume(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case SET_VIDEO_WINDOW:
Packit 1fb8d4
					error = tsmf_ifman_set_video_window(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case UPDATE_GEOMETRY_INFO:
Packit 1fb8d4
					error = tsmf_ifman_update_geometry_info(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case SET_ALLOCATOR:
Packit 1fb8d4
					error = tsmf_ifman_set_allocator(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case NOTIFY_PREROLL:
Packit 1fb8d4
					error = tsmf_ifman_notify_preroll(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_SAMPLE:
Packit 1fb8d4
					error = tsmf_ifman_on_sample(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_FLUSH:
Packit 1fb8d4
					error = tsmf_ifman_on_flush(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_END_OF_STREAM:
Packit 1fb8d4
					error = tsmf_ifman_on_end_of_stream(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_PLAYBACK_STARTED:
Packit 1fb8d4
					error = tsmf_ifman_on_playback_started(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_PLAYBACK_PAUSED:
Packit 1fb8d4
					error = tsmf_ifman_on_playback_paused(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_PLAYBACK_RESTARTED:
Packit 1fb8d4
					error = tsmf_ifman_on_playback_restarted(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_PLAYBACK_STOPPED:
Packit 1fb8d4
					error = tsmf_ifman_on_playback_stopped(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case ON_PLAYBACK_RATE_CHANGED:
Packit 1fb8d4
					error = tsmf_ifman_on_playback_rate_changed(&ifman);
Packit 1fb8d4
					processed = TRUE;
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				case RIMCALL_RELEASE:
Packit 1fb8d4
				case RIMCALL_QUERYINTERFACE:
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				default:
Packit 1fb8d4
					break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	input = NULL;
Packit 1fb8d4
	ifman.input = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (error)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "ifman data received processing error %" PRIu32 "", error);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!processed)
Packit 1fb8d4
	{
Packit 1fb8d4
		switch (FunctionId)
Packit 1fb8d4
		{
Packit 1fb8d4
			case RIMCALL_RELEASE:
Packit 1fb8d4
				/* [MS-RDPEXPS] 2.2.2.2 Interface Release (IFACE_RELEASE)
Packit 1fb8d4
				   This message does not require a reply. */
Packit 1fb8d4
				processed = TRUE;
Packit 1fb8d4
				ifman.output_pending = 1;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case RIMCALL_QUERYINTERFACE:
Packit 1fb8d4
				/* [MS-RDPEXPS] 2.2.2.1.2 Query Interface Response (QI_RSP)
Packit 1fb8d4
				   This message is not supported in this channel. */
Packit 1fb8d4
				processed = TRUE;
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!processed)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG,
Packit Service 5a9772
			         "Unknown InterfaceId: 0x%08" PRIX32 " MessageId: 0x%08" PRIX32
Packit Service 5a9772
			         " FunctionId: 0x%08" PRIX32 "\n",
Packit 1fb8d4
			         InterfaceId, MessageId, FunctionId);
Packit 1fb8d4
			/* When a request is not implemented we return empty response indicating error */
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		processed = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (processed && !ifman.output_pending)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Response packet does not have FunctionId */
Packit 1fb8d4
		length = Stream_GetPosition(output);
Packit 1fb8d4
		Stream_SetPosition(output, 0);
Packit 1fb8d4
		Stream_Write_UINT32(output, ifman.output_interface_id);
Packit 1fb8d4
		Stream_Write_UINT32(output, MessageId);
Packit 1fb8d4
		DEBUG_TSMF("response size %d", length);
Packit 1fb8d4
		error = callback->channel->Write(callback->channel, length, Stream_Buffer(output), NULL);
Packit 1fb8d4
Packit 1fb8d4
		if (error)
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "response error %" PRIu32 "", error);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
out:
Packit 1fb8d4
	Stream_Free(output, 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
static UINT tsmf_on_close(IWTSVirtualChannelCallback* pChannelCallback)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_STREAM* stream;
Packit 1fb8d4
	TSMF_PRESENTATION* presentation;
Packit Service 5a9772
	TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*)pChannelCallback;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
Packit 1fb8d4
	if (callback->stream_id)
Packit 1fb8d4
	{
Packit 1fb8d4
		presentation = tsmf_presentation_find_by_id(callback->presentation_id);
Packit 1fb8d4
Packit 1fb8d4
		if (presentation)
Packit 1fb8d4
		{
Packit 1fb8d4
			stream = tsmf_stream_find_by_id(presentation, callback->stream_id);
Packit 1fb8d4
Packit 1fb8d4
			if (stream)
Packit 1fb8d4
				tsmf_stream_free(stream);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(pChannelCallback);
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
static UINT tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
Packit Service 5a9772
                                           IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
Packit Service 5a9772
                                           IWTSVirtualChannelCallback** ppCallback)
Packit 1fb8d4
{
Packit 1fb8d4
	TSMF_CHANNEL_CALLBACK* callback;
Packit Service 5a9772
	TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*)pListenerCallback;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit Service 5a9772
	callback = (TSMF_CHANNEL_CALLBACK*)calloc(1, sizeof(TSMF_CHANNEL_CALLBACK));
Packit 1fb8d4
Packit 1fb8d4
	if (!callback)
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
	callback->iface.OnDataReceived = tsmf_on_data_received;
Packit 1fb8d4
	callback->iface.OnClose = tsmf_on_close;
Packit 1fb8d4
	callback->iface.OnOpen = NULL;
Packit 1fb8d4
	callback->plugin = listener_callback->plugin;
Packit 1fb8d4
	callback->channel_mgr = listener_callback->channel_mgr;
Packit 1fb8d4
	callback->channel = pChannel;
Packit Service 5a9772
	*ppCallback = (IWTSVirtualChannelCallback*)callback;
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
static UINT tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT status;
Packit Service 5a9772
	TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*)pPlugin;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit Service 5a9772
	tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*)calloc(1, sizeof(TSMF_LISTENER_CALLBACK));
Packit 1fb8d4
Packit 1fb8d4
	if (!tsmf->listener_callback)
Packit 1fb8d4
		return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
Packit 1fb8d4
	tsmf->listener_callback->iface.OnNewChannelConnection = tsmf_on_new_channel_connection;
Packit 1fb8d4
	tsmf->listener_callback->plugin = pPlugin;
Packit 1fb8d4
	tsmf->listener_callback->channel_mgr = pChannelMgr;
Packit Service 5a9772
	status = pChannelMgr->CreateListener(
Packit Service 5a9772
	    pChannelMgr, "TSMF", 0, (IWTSListenerCallback*)tsmf->listener_callback, &(tsmf->listener));
Packit 1fb8d4
	tsmf->listener->pInterface = tsmf->iface.pInterface;
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
static UINT tsmf_plugin_terminated(IWTSPlugin* pPlugin)
Packit 1fb8d4
{
Packit Service 5a9772
	TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*)pPlugin;
Packit 1fb8d4
	DEBUG_TSMF("");
Packit 1fb8d4
	free(tsmf->listener_callback);
Packit 1fb8d4
	free(tsmf);
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
static UINT tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	DWORD flags;
Packit 1fb8d4
	COMMAND_LINE_ARGUMENT_A* arg;
Packit Service 5a9772
	TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*)pPlugin;
Packit Service 5a9772
	COMMAND_LINE_ARGUMENT_A tsmf_args[] = { { "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>",
Packit Service 5a9772
		                                      NULL, NULL, -1, NULL, "audio subsystem" },
Packit Service 5a9772
		                                    { "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL,
Packit Service 5a9772
		                                      NULL, -1, NULL, "audio device name" },
Packit Service 5a9772
		                                    { "decoder", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>",
Packit Service 5a9772
		                                      NULL, NULL, -1, NULL, "decoder subsystem" },
Packit Service 5a9772
		                                    { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } };
Packit 1fb8d4
	flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
Packit Service 5a9772
	status = CommandLineParseArgumentsA(args->argc, args->argv, tsmf_args, flags, tsmf, NULL, NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (status != 0)
Packit 1fb8d4
		return ERROR_INVALID_DATA;
Packit 1fb8d4
Packit 1fb8d4
	arg = tsmf_args;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit Service 5a9772
		CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "sys")
Packit 1fb8d4
		{
Packit 1fb8d4
			tsmf->audio_name = _strdup(arg->Value);
Packit 1fb8d4
Packit 1fb8d4
			if (!tsmf->audio_name)
Packit 1fb8d4
				return ERROR_OUTOFMEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "dev")
Packit 1fb8d4
		{
Packit 1fb8d4
			tsmf->audio_device = _strdup(arg->Value);
Packit 1fb8d4
Packit 1fb8d4
			if (!tsmf->audio_device)
Packit 1fb8d4
				return ERROR_OUTOFMEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "decoder")
Packit 1fb8d4
		{
Packit 1fb8d4
			tsmf->decoder_name = _strdup(arg->Value);
Packit 1fb8d4
Packit 1fb8d4
			if (!tsmf->decoder_name)
Packit 1fb8d4
				return ERROR_OUTOFMEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchDefault(arg)
Packit 1fb8d4
		{
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchEnd(arg)
Packit Service 5a9772
	} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
Packit 1fb8d4
Packit 1fb8d4
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#ifdef BUILTIN_CHANNELS
Packit Service 5a9772
#define DVCPluginEntry tsmf_DVCPluginEntry
Packit 1fb8d4
#else
Packit Service 5a9772
#define DVCPluginEntry FREERDP_API DVCPluginEntry
Packit 1fb8d4
#endif
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 DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT status = 0;
Packit 1fb8d4
	TSMF_PLUGIN* tsmf;
Packit 1fb8d4
	TsmfClientContext* context;
Packit 1fb8d4
	UINT error = CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
	tsmf = (TSMF_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "tsmf");
Packit 1fb8d4
Packit 1fb8d4
	if (!tsmf)
Packit 1fb8d4
	{
Packit Service 5a9772
		tsmf = (TSMF_PLUGIN*)calloc(1, sizeof(TSMF_PLUGIN));
Packit 1fb8d4
Packit 1fb8d4
		if (!tsmf)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
			return CHANNEL_RC_NO_MEMORY;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		tsmf->iface.Initialize = tsmf_plugin_initialize;
Packit 1fb8d4
		tsmf->iface.Connected = NULL;
Packit 1fb8d4
		tsmf->iface.Disconnected = NULL;
Packit 1fb8d4
		tsmf->iface.Terminated = tsmf_plugin_terminated;
Packit Service 5a9772
		tsmf->rdpcontext =
Packit Service 5a9772
		    ((freerdp*)((rdpSettings*)pEntryPoints->GetRdpSettings(pEntryPoints))->instance)
Packit Service 5a9772
		        ->context;
Packit Service 5a9772
		context = (TsmfClientContext*)calloc(1, sizeof(TsmfClientContext));
Packit 1fb8d4
Packit 1fb8d4
		if (!context)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "calloc failed!");
Packit 1fb8d4
			goto error_context;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		context->handle = (void*)tsmf;
Packit Service 5a9772
		tsmf->iface.pInterface = (void*)context;
Packit 1fb8d4
Packit 1fb8d4
		if (!tsmf_media_init())
Packit 1fb8d4
		{
Packit 1fb8d4
			error = ERROR_INVALID_OPERATION;
Packit 1fb8d4
			goto error_init;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin*)tsmf);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (status == CHANNEL_RC_OK)
Packit 1fb8d4
	{
Packit Service 5a9772
		status =
Packit Service 5a9772
		    tsmf_process_addin_args((IWTSPlugin*)tsmf, pEntryPoints->GetPluginData(pEntryPoints));
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
error_init:
Packit 1fb8d4
	free(context);
Packit 1fb8d4
error_context:
Packit 1fb8d4
	free(tsmf);
Packit 1fb8d4
	return error;
Packit 1fb8d4
}