FreeRDP/channels/tsmf/client/tsmf_main.c

432 lines
12 KiB
C
Raw Normal View History

2011-09-19 18:54:09 +04:00
/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
2011-09-19 18:54:09 +04:00
* Video Redirection Virtual Channel
*
* Copyright 2010-2011 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2011-09-19 18:54:09 +04:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/cmdline.h>
#include <winpr/stream.h>
2011-09-19 18:54:09 +04:00
#include "tsmf_types.h"
2011-09-19 18:54:09 +04:00
#include "tsmf_constants.h"
#include "tsmf_ifman.h"
#include "tsmf_media.h"
#include "tsmf_main.h"
typedef struct _TSMF_LISTENER_CALLBACK TSMF_LISTENER_CALLBACK;
typedef struct _TSMF_CHANNEL_CALLBACK TSMF_CHANNEL_CALLBACK;
typedef struct _TSMF_PLUGIN TSMF_PLUGIN;
struct _TSMF_LISTENER_CALLBACK
{
IWTSListenerCallback iface;
IWTSPlugin *plugin;
IWTSVirtualChannelManager *channel_mgr;
2011-09-19 18:54:09 +04:00
};
struct _TSMF_CHANNEL_CALLBACK
{
IWTSVirtualChannelCallback iface;
IWTSPlugin *plugin;
IWTSVirtualChannelManager *channel_mgr;
IWTSVirtualChannel *channel;
2011-09-19 18:54:09 +04:00
BYTE presentation_id[GUID_SIZE];
2012-10-09 11:26:39 +04:00
UINT32 stream_id;
2011-09-19 18:54:09 +04:00
};
struct _TSMF_PLUGIN
{
IWTSPlugin iface;
TSMF_LISTENER_CALLBACK *listener_callback;
2011-09-19 18:54:09 +04:00
const char *decoder_name;
const char *audio_name;
const char *audio_device;
2011-09-19 18:54:09 +04:00
};
void tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback,
UINT32 message_id, UINT64 duration, UINT32 data_size)
2011-09-19 18:54:09 +04:00
{
wStream *s;
int status = -1;
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
2013-05-09 01:48:30 +04:00
s = Stream_New(NULL, 32);
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY);
Stream_Write_UINT32(s, message_id);
Stream_Write_UINT32(s, PLAYBACK_ACK); /* FunctionId */
Stream_Write_UINT32(s, callback->stream_id); /* StreamId */
Stream_Write_UINT64(s, duration); /* DataDuration */
Stream_Write_UINT64(s, data_size); /* cbData */
DEBUG_TSMF("response size %d", (int) Stream_GetPosition(s));
if(!callback || !callback->channel || !callback->channel->Write)
WLog_ERR(TAG, "callback=%p, channel=%p, write=%p", callback,
callback->channel, callback->channel->Write);
else
status = callback->channel->Write(callback->channel,
Stream_GetPosition(s), Stream_Buffer(s), NULL);
if(status)
2011-09-19 18:54:09 +04:00
{
WLog_ERR(TAG, "response error %d", status);
2011-09-19 18:54:09 +04:00
}
2013-05-09 01:48:30 +04:00
Stream_Free(s, TRUE);
2011-09-19 18:54:09 +04:00
}
BOOL tsmf_push_event(IWTSVirtualChannelCallback *pChannelCallback, wMessage *event)
2011-09-19 18:54:09 +04:00
{
int status;
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
status = callback->channel_mgr->PushEvent(callback->channel_mgr, event);
if(status)
2011-09-19 18:54:09 +04:00
{
WLog_ERR(TAG, "response error %d", status);
return FALSE;
2011-09-19 18:54:09 +04:00
}
return TRUE;
2011-09-19 18:54:09 +04:00
}
static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
2011-09-19 18:54:09 +04:00
{
int length;
wStream *input;
wStream *output;
int status = -1;
2011-09-19 18:54:09 +04:00
TSMF_IFMAN ifman;
2012-10-09 11:26:39 +04:00
UINT32 MessageId;
UINT32 FunctionId;
UINT32 InterfaceId;
2011-09-19 18:54:09 +04:00
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
UINT32 cbSize = Stream_GetRemainingLength(data);
2011-09-19 18:54:09 +04:00
/* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */
if(cbSize < 12)
2011-09-19 18:54:09 +04:00
{
WLog_ERR(TAG, "invalid size. cbSize=%d", cbSize);
2011-09-19 18:54:09 +04:00
return 1;
}
2013-05-09 01:48:30 +04:00
input = data;
2013-05-09 01:48:30 +04:00
output = Stream_New(NULL, 256);
Stream_Seek(output, 8);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(input, InterfaceId);
Stream_Read_UINT32(input, MessageId);
Stream_Read_UINT32(input, FunctionId);
DEBUG_TSMF("cbSize=%d InterfaceId=0x%X MessageId=0x%X FunctionId=0x%X",
cbSize, InterfaceId, MessageId, FunctionId);
2011-09-19 18:54:09 +04:00
memset(&ifman, 0, sizeof(TSMF_IFMAN));
ifman.channel_callback = pChannelCallback;
ifman.decoder_name = ((TSMF_PLUGIN *) callback->plugin)->decoder_name;
ifman.audio_name = ((TSMF_PLUGIN *) callback->plugin)->audio_name;
ifman.audio_device = ((TSMF_PLUGIN *) callback->plugin)->audio_device;
memcpy(ifman.presentation_id, callback->presentation_id, GUID_SIZE);
2011-09-19 18:54:09 +04:00
ifman.stream_id = callback->stream_id;
ifman.message_id = MessageId;
ifman.input = input;
ifman.input_size = cbSize - 12;
ifman.output = output;
ifman.output_pending = FALSE;
2011-09-19 18:54:09 +04:00
ifman.output_interface_id = InterfaceId;
switch(InterfaceId)
2011-09-19 18:54:09 +04:00
{
case TSMF_INTERFACE_CAPABILITIES | STREAM_ID_NONE:
switch(FunctionId)
2011-09-19 18:54:09 +04:00
{
case RIM_EXCHANGE_CAPABILITY_REQUEST:
status = tsmf_ifman_rim_exchange_capability_request(&ifman);
2011-09-19 18:54:09 +04:00
break;
default:
break;
}
break;
case TSMF_INTERFACE_DEFAULT | STREAM_ID_PROXY:
switch(FunctionId)
2011-09-19 18:54:09 +04:00
{
case SET_CHANNEL_PARAMS:
memcpy(callback->presentation_id, Stream_Pointer(input), GUID_SIZE);
Stream_Seek(input, GUID_SIZE);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(input, callback->stream_id);
DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%d", callback->stream_id);
ifman.output_pending = TRUE;
status = 0;
2011-09-19 18:54:09 +04:00
break;
case EXCHANGE_CAPABILITIES_REQ:
status = tsmf_ifman_exchange_capability_request(&ifman);
2011-09-19 18:54:09 +04:00
break;
case CHECK_FORMAT_SUPPORT_REQ:
status = tsmf_ifman_check_format_support_request(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_NEW_PRESENTATION:
status = tsmf_ifman_on_new_presentation(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ADD_STREAM:
status = tsmf_ifman_add_stream(&ifman);
2011-09-19 18:54:09 +04:00
break;
case SET_TOPOLOGY_REQ:
status = tsmf_ifman_set_topology_request(&ifman);
2011-09-19 18:54:09 +04:00
break;
case REMOVE_STREAM:
status = tsmf_ifman_remove_stream(&ifman);
2011-09-19 18:54:09 +04:00
break;
case SET_SOURCE_VIDEO_RECT:
status = tsmf_ifman_set_source_video_rect(&ifman);
break;
2011-09-19 18:54:09 +04:00
case SHUTDOWN_PRESENTATION_REQ:
status = tsmf_ifman_shutdown_presentation(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_STREAM_VOLUME:
status = tsmf_ifman_on_stream_volume(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_CHANNEL_VOLUME:
status = tsmf_ifman_on_channel_volume(&ifman);
2011-09-19 18:54:09 +04:00
break;
case SET_VIDEO_WINDOW:
status = tsmf_ifman_set_video_window(&ifman);
2011-09-19 18:54:09 +04:00
break;
case UPDATE_GEOMETRY_INFO:
status = tsmf_ifman_update_geometry_info(&ifman);
2011-09-19 18:54:09 +04:00
break;
case SET_ALLOCATOR:
status = tsmf_ifman_set_allocator(&ifman);
2011-09-19 18:54:09 +04:00
break;
case NOTIFY_PREROLL:
status = tsmf_ifman_notify_preroll(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_SAMPLE:
status = tsmf_ifman_on_sample(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_FLUSH:
status = tsmf_ifman_on_flush(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_END_OF_STREAM:
status = tsmf_ifman_on_end_of_stream(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_PLAYBACK_STARTED:
status = tsmf_ifman_on_playback_started(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_PLAYBACK_PAUSED:
status = tsmf_ifman_on_playback_paused(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_PLAYBACK_RESTARTED:
status = tsmf_ifman_on_playback_restarted(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_PLAYBACK_STOPPED:
status = tsmf_ifman_on_playback_stopped(&ifman);
2011-09-19 18:54:09 +04:00
break;
case ON_PLAYBACK_RATE_CHANGED:
status = tsmf_ifman_on_playback_rate_changed(&ifman);
2011-09-19 18:54:09 +04:00
break;
default:
break;
}
break;
default:
break;
}
input = NULL;
ifman.input = NULL;
if(status == -1)
2011-09-19 18:54:09 +04:00
{
switch(FunctionId)
2011-09-19 18:54:09 +04:00
{
case RIMCALL_RELEASE:
/* [MS-RDPEXPS] 2.2.2.2 Interface Release (IFACE_RELEASE)
This message does not require a reply. */
status = 0;
2011-09-19 18:54:09 +04:00
ifman.output_pending = 1;
break;
case RIMCALL_QUERYINTERFACE:
/* [MS-RDPEXPS] 2.2.2.1.2 Query Interface Response (QI_RSP)
This message is not supported in this channel. */
status = 0;
2011-09-19 18:54:09 +04:00
break;
}
if(status == -1)
2011-09-19 18:54:09 +04:00
{
WLog_ERR(TAG, "InterfaceId 0x%X FunctionId 0x%X not processed.",
InterfaceId, FunctionId);
2011-09-19 18:54:09 +04:00
/* When a request is not implemented we return empty response indicating error */
}
status = 0;
2011-09-19 18:54:09 +04:00
}
if(status == 0 && !ifman.output_pending)
2011-09-19 18:54:09 +04:00
{
/* Response packet does not have FunctionId */
length = Stream_GetPosition(output);
Stream_SetPosition(output, 0);
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(output, ifman.output_interface_id);
Stream_Write_UINT32(output, MessageId);
DEBUG_TSMF("response size %d", length);
2013-05-09 00:27:21 +04:00
status = callback->channel->Write(callback->channel, length, Stream_Buffer(output), NULL);
if(status)
2011-09-19 18:54:09 +04:00
{
WLog_ERR(TAG, "response error %d", status);
2011-09-19 18:54:09 +04:00
}
}
2013-05-09 01:48:30 +04:00
Stream_Free(output, TRUE);
return status;
2011-09-19 18:54:09 +04:00
}
static int tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback)
2011-09-19 18:54:09 +04:00
{
TSMF_STREAM *stream;
TSMF_PRESENTATION *presentation;
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
DEBUG_TSMF("");
if(callback->stream_id)
2011-09-19 18:54:09 +04:00
{
presentation = tsmf_presentation_find_by_id(callback->presentation_id);
if(presentation)
2011-09-19 18:54:09 +04:00
{
stream = tsmf_stream_find_by_id(presentation, callback->stream_id);
if(stream)
2011-09-19 18:54:09 +04:00
tsmf_stream_free(stream);
}
}
free(pChannelCallback);
2011-09-19 18:54:09 +04:00
return 0;
}
static int tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallback,
IWTSVirtualChannel *pChannel,
BYTE *Data,
int *pbAccept,
IWTSVirtualChannelCallback **ppCallback)
2011-09-19 18:54:09 +04:00
{
TSMF_CHANNEL_CALLBACK *callback;
TSMF_LISTENER_CALLBACK *listener_callback = (TSMF_LISTENER_CALLBACK *) pListenerCallback;
DEBUG_TSMF("");
callback = (TSMF_CHANNEL_CALLBACK *) malloc(sizeof(TSMF_CHANNEL_CALLBACK));
ZeroMemory(callback, sizeof(TSMF_CHANNEL_CALLBACK));
2011-09-19 18:54:09 +04:00
callback->iface.OnDataReceived = tsmf_on_data_received;
callback->iface.OnClose = tsmf_on_close;
callback->iface.OnOpen = NULL;
2011-09-19 18:54:09 +04:00
callback->plugin = listener_callback->plugin;
callback->channel_mgr = listener_callback->channel_mgr;
callback->channel = pChannel;
*ppCallback = (IWTSVirtualChannelCallback *) callback;
2011-09-19 18:54:09 +04:00
return 0;
}
static int tsmf_plugin_initialize(IWTSPlugin *pPlugin, IWTSVirtualChannelManager *pChannelMgr)
2011-09-19 18:54:09 +04:00
{
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
DEBUG_TSMF("");
tsmf->listener_callback = (TSMF_LISTENER_CALLBACK *) malloc(sizeof(TSMF_LISTENER_CALLBACK));
ZeroMemory(tsmf->listener_callback, sizeof(TSMF_LISTENER_CALLBACK));
2011-09-19 18:54:09 +04:00
tsmf->listener_callback->iface.OnNewChannelConnection = tsmf_on_new_channel_connection;
tsmf->listener_callback->plugin = pPlugin;
tsmf->listener_callback->channel_mgr = pChannelMgr;
return pChannelMgr->CreateListener(pChannelMgr, "TSMF", 0,
(IWTSListenerCallback *) tsmf->listener_callback, NULL);
2011-09-19 18:54:09 +04:00
}
static int tsmf_plugin_terminated(IWTSPlugin *pPlugin)
2011-09-19 18:54:09 +04:00
{
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
DEBUG_TSMF("");
if(tsmf->listener_callback)
free(tsmf->listener_callback);
free(tsmf);
2011-09-19 18:54:09 +04:00
return 0;
}
COMMAND_LINE_ARGUMENT_A tsmf_args[] =
{
{ "audio", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "audio subsystem" },
{ "audio-dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "audio device name" },
{ "decoder", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "decoder subsystem" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
static void tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args)
2011-09-19 18:54:09 +04:00
{
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A *arg;
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
status = CommandLineParseArgumentsA(args->argc, (const char **) args->argv,
tsmf_args, flags, tsmf, NULL, NULL);
arg = tsmf_args;
do
2011-09-19 18:54:09 +04:00
{
if(!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "audio")
2011-09-19 18:54:09 +04:00
{
tsmf->audio_name = _strdup(arg->Value);
}
CommandLineSwitchCase(arg, "audio-dev")
{
tsmf->audio_device = _strdup(arg->Value);
2011-09-19 18:54:09 +04:00
}
CommandLineSwitchCase(arg, "decoder")
{
tsmf->decoder_name = _strdup(arg->Value);
}
CommandLineSwitchDefault(arg)
{
}
CommandLineSwitchEnd(arg)
2011-09-19 18:54:09 +04:00
}
while((arg = CommandLineFindNextArgumentA(arg)) != NULL);
2011-09-19 18:54:09 +04:00
}
2012-10-14 10:38:58 +04:00
#ifdef STATIC_CHANNELS
#define DVCPluginEntry tsmf_DVCPluginEntry
#endif
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS *pEntryPoints)
2011-09-19 18:54:09 +04:00
{
int status = 0;
TSMF_PLUGIN *tsmf;
tsmf = (TSMF_PLUGIN *) pEntryPoints->GetPlugin(pEntryPoints, "tsmf");
if(tsmf == NULL)
2011-09-19 18:54:09 +04:00
{
tsmf = (TSMF_PLUGIN *) malloc(sizeof(TSMF_PLUGIN));
ZeroMemory(tsmf, sizeof(TSMF_PLUGIN));
2011-09-19 18:54:09 +04:00
tsmf->iface.Initialize = tsmf_plugin_initialize;
tsmf->iface.Connected = NULL;
tsmf->iface.Disconnected = NULL;
tsmf->iface.Terminated = tsmf_plugin_terminated;
status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin *) tsmf);
2011-09-19 18:54:09 +04:00
tsmf_media_init();
}
if(status == 0)
2011-09-19 18:54:09 +04:00
{
tsmf_process_addin_args((IWTSPlugin *) tsmf, pEntryPoints->GetPluginData(pEntryPoints));
2011-09-19 18:54:09 +04:00
}
return status;
2011-09-19 18:54:09 +04:00
}