Merge branch 'master' of https://github.com/awakecoding/FreeRDP into awakecoding
This commit is contained in:
commit
38c39e172e
@ -76,11 +76,11 @@ if(ANDROID OR IOS)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
|
||||
endif(ANDROID OR IOS)
|
||||
include(GetGitRevisionDescription)
|
||||
git_describe(GIT_REVISION --match "[0-9]*" --abbrev=4 --tags --always)
|
||||
if(ANDROID OR IOS)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||
endif(ANDROID OR IOS)
|
||||
|
||||
git_describe(GIT_REVISION --match "[0-9]*" --abbrev=4 --tags --always)
|
||||
message(STATUS "Git Revision ${GIT_REVISION}")
|
||||
|
||||
# Turn on solution folders (2.8.4+)
|
||||
@ -417,9 +417,13 @@ set(FFMPEG_FEATURE_TYPE "RECOMMENDED")
|
||||
set(FFMPEG_FEATURE_PURPOSE "multimedia")
|
||||
set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
||||
|
||||
set(GSTREAMER_FEATURE_TYPE "RECOMMENDED")
|
||||
set(GSTREAMER_FEATURE_PURPOSE "multimedia")
|
||||
set(GSTREAMER_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia")
|
||||
set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version")
|
||||
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "RECOMMENDED")
|
||||
set(GSTREAMER_1_0_FEATURE_PURPOSE "multimedia")
|
||||
set(GSTREAMER_1_0_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
||||
|
||||
set(IPP_FEATURE_TYPE "OPTIONAL")
|
||||
set(IPP_FEATURE_PURPOSE "performance")
|
||||
@ -442,14 +446,15 @@ if(WIN32)
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
|
||||
set(OPENSLES_FEATURE_TYPE "DISABLED")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSTREAMER_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL")
|
||||
set(X11_FEATURE_TYPE "OPTIONAL")
|
||||
if(IOS)
|
||||
set(X11_FEATURE_TYPE "DISABLED")
|
||||
@ -457,7 +462,8 @@ if(APPLE)
|
||||
set(PULSE_FEATURE_TYPE "DISABLED")
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
|
||||
endif()
|
||||
set(OPENSLES_FEATURE_TYPE "DISABLED")
|
||||
endif()
|
||||
@ -470,7 +476,8 @@ if(ANDROID)
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
|
||||
set(OPENSLES_FEATURE_TYPE "REQUIRED")
|
||||
endif()
|
||||
|
||||
@ -492,7 +499,9 @@ find_feature(Cups ${CUPS_FEATURE_TYPE} ${CUPS_FEATURE_PURPOSE} ${CUPS_FEATURE_DE
|
||||
find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DESCRIPTION})
|
||||
|
||||
find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION})
|
||||
find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION})
|
||||
|
||||
find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEATURE_PURPOSE} ${GSTREAMER_0_10_FEATURE_DESCRIPTION})
|
||||
find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION})
|
||||
|
||||
find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION})
|
||||
find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION})
|
||||
|
@ -312,34 +312,31 @@ static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallb
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
|
||||
static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||
{
|
||||
int error;
|
||||
wStream* s;
|
||||
BYTE MessageId;
|
||||
|
||||
s = Stream_New(pBuffer, cbSize);
|
||||
|
||||
Stream_Read_UINT8(s, MessageId);
|
||||
Stream_Read_UINT8(data, MessageId);
|
||||
|
||||
DEBUG_DVC("MessageId=0x%x", MessageId);
|
||||
|
||||
switch (MessageId)
|
||||
{
|
||||
case MSG_SNDIN_VERSION:
|
||||
error = audin_process_version(pChannelCallback, s);
|
||||
error = audin_process_version(pChannelCallback, data);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATS:
|
||||
error = audin_process_formats(pChannelCallback, s);
|
||||
error = audin_process_formats(pChannelCallback, data);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_OPEN:
|
||||
error = audin_process_open(pChannelCallback, s);
|
||||
error = audin_process_open(pChannelCallback, data);
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATCHANGE:
|
||||
error = audin_process_format_change(pChannelCallback, s);
|
||||
error = audin_process_format_change(pChannelCallback, data);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -348,8 +345,6 @@ static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_Free(s, FALSE);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -77,9 +77,11 @@ static void audin_server_select_format(audin_server_context* context, int client
|
||||
|
||||
static void audin_server_send_version(audin_server* audin, wStream* s)
|
||||
{
|
||||
ULONG written;
|
||||
|
||||
Stream_Write_UINT8(s, MSG_SNDIN_VERSION);
|
||||
Stream_Write_UINT32(s, 1); /* Version (4 bytes) */
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
|
||||
@ -101,6 +103,7 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
|
||||
{
|
||||
int i;
|
||||
UINT32 nAvgBytesPerSec;
|
||||
ULONG written;
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
Stream_Write_UINT8(s, MSG_SNDIN_FORMATS);
|
||||
@ -131,7 +134,7 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
|
||||
}
|
||||
}
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
|
||||
@ -181,6 +184,8 @@ static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 le
|
||||
|
||||
static void audin_server_send_open(audin_server* audin, wStream* s)
|
||||
{
|
||||
ULONG written;
|
||||
|
||||
if (audin->context.selected_client_format < 0)
|
||||
return;
|
||||
|
||||
@ -203,7 +208,7 @@ static void audin_server_send_open(audin_server* audin, wStream* s)
|
||||
Stream_Write_UINT16(s, 16); /* wBitsPerSample */
|
||||
Stream_Write_UINT16(s, 0); /* cbSize */
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
|
||||
|
@ -31,7 +31,6 @@
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
|
||||
#include "cliprdr_main.h"
|
||||
|
@ -31,7 +31,6 @@
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/client/cliprdr.h>
|
||||
|
||||
#include "cliprdr_main.h"
|
||||
@ -382,8 +381,6 @@ static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
||||
DEBUG_WARN("unknown msgType %d", msgType);
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
static void cliprdr_process_filecontents_request_event(cliprdrPlugin* plugin, RDP_CB_FILECONTENTS_REQUEST_EVENT * event)
|
||||
@ -506,6 +503,7 @@ static void cliprdr_process_event(rdpSvcPlugin* plugin, wMessage* event)
|
||||
|
||||
static void cliprdr_process_terminate(rdpSvcPlugin* plugin)
|
||||
{
|
||||
svc_plugin_terminate(plugin);
|
||||
free(plugin);
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/utils/debug.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
struct cliprdr_plugin
|
||||
{
|
||||
|
@ -68,6 +68,7 @@ static int cliprdr_server_send_capabilities(CliprdrServerContext* context)
|
||||
BOOL status;
|
||||
UINT32 generalFlags;
|
||||
CLIPRDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("CliprdrServerSendCapabilities\n");
|
||||
|
||||
@ -96,7 +97,7 @@ static int cliprdr_server_send_capabilities(CliprdrServerContext* context)
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
@ -108,6 +109,7 @@ static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context)
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
CLIPRDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("CliprdrServerSendMonitorReady\n");
|
||||
|
||||
@ -123,7 +125,7 @@ static int cliprdr_server_send_monitor_ready(CliprdrServerContext* context)
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
@ -135,6 +137,7 @@ static int cliprdr_server_send_format_list_response(CliprdrServerContext* contex
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
CLIPRDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("CliprdrServerSendFormatListResponse\n");
|
||||
|
||||
@ -150,7 +153,7 @@ static int cliprdr_server_send_format_list_response(CliprdrServerContext* contex
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
|
@ -83,11 +83,7 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
|
||||
|
||||
disp = (DISP_PLUGIN*) callback->plugin;
|
||||
|
||||
#ifdef DISP_PREVIEW
|
||||
MonitorLayoutSize = 32;
|
||||
#else
|
||||
MonitorLayoutSize = 40;
|
||||
#endif
|
||||
|
||||
length = 8 + 8 + (NumMonitors * MonitorLayoutSize);
|
||||
|
||||
@ -101,11 +97,7 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
|
||||
if (NumMonitors > disp->MaxNumMonitors)
|
||||
NumMonitors = disp->MaxNumMonitors;
|
||||
|
||||
#ifdef DISP_PREVIEW
|
||||
Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */
|
||||
#else
|
||||
Stream_Write_UINT32(s, MonitorLayoutSize); /* MonitorLayoutSize (4 bytes) */
|
||||
#endif
|
||||
|
||||
Stream_Write_UINT32(s, NumMonitors); /* NumMonitors (4 bytes) */
|
||||
|
||||
@ -147,10 +139,8 @@ int disp_send_display_control_monitor_layout_pdu(DISP_CHANNEL_CALLBACK* callback
|
||||
fprintf(stderr, "\t: Orientation: %d\n", Monitors[index].Orientation);
|
||||
#endif
|
||||
|
||||
#ifndef DISP_PREVIEW
|
||||
Stream_Write_UINT32(s, Monitors[index].DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
|
||||
Stream_Write_UINT32(s, Monitors[index].DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */
|
||||
#endif
|
||||
}
|
||||
|
||||
Stream_SealLength(s);
|
||||
@ -201,17 +191,12 @@ int disp_recv_pdu(DISP_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
|
||||
static int disp_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||
{
|
||||
wStream* s;
|
||||
int status = 0;
|
||||
DISP_CHANNEL_CALLBACK* callback = (DISP_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
s = Stream_New(pBuffer, cbSize);
|
||||
|
||||
status = disp_recv_pdu(callback, s);
|
||||
|
||||
Stream_Free(s, FALSE);
|
||||
status = disp_recv_pdu(callback, data);
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -308,33 +293,34 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
|
||||
disp = (DISP_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "disp");
|
||||
|
||||
if (disp == NULL)
|
||||
if (!disp)
|
||||
{
|
||||
disp = (DISP_PLUGIN*) malloc(sizeof(DISP_PLUGIN));
|
||||
disp = (DISP_PLUGIN*) calloc(1, sizeof(DISP_PLUGIN));
|
||||
|
||||
if (disp)
|
||||
{
|
||||
ZeroMemory(disp, sizeof(DISP_PLUGIN));
|
||||
if (!disp)
|
||||
return -1;
|
||||
|
||||
disp->iface.Initialize = disp_plugin_initialize;
|
||||
disp->iface.Connected = NULL;
|
||||
disp->iface.Disconnected = NULL;
|
||||
disp->iface.Terminated = disp_plugin_terminated;
|
||||
disp->iface.Initialize = disp_plugin_initialize;
|
||||
disp->iface.Connected = NULL;
|
||||
disp->iface.Disconnected = NULL;
|
||||
disp->iface.Terminated = disp_plugin_terminated;
|
||||
|
||||
context = (DispClientContext*) malloc(sizeof(DispClientContext));
|
||||
context = (DispClientContext*) calloc(1, sizeof(DispClientContext));
|
||||
|
||||
context->handle = (void*) disp;
|
||||
if (!context)
|
||||
return -1;
|
||||
|
||||
context->SendMonitorLayout = disp_send_monitor_layout;
|
||||
context->handle = (void*) disp;
|
||||
|
||||
disp->iface.pInterface = (void*) context;
|
||||
context->SendMonitorLayout = disp_send_monitor_layout;
|
||||
|
||||
disp->MaxNumMonitors = 16;
|
||||
disp->MaxMonitorWidth = 8192;
|
||||
disp->MaxMonitorHeight = 8192;
|
||||
disp->iface.pInterface = (void*) context;
|
||||
|
||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp);
|
||||
}
|
||||
disp->MaxNumMonitors = 16;
|
||||
disp->MaxMonitorWidth = 8192;
|
||||
disp->MaxMonitorHeight = 8192;
|
||||
|
||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "disp", (IWTSPlugin*) disp);
|
||||
}
|
||||
|
||||
return error;
|
||||
|
@ -34,7 +34,5 @@
|
||||
#define DISPLAY_CONTROL_PDU_TYPE_MONITOR_LAYOUT 0x00000002
|
||||
#define DISPLAY_CONTROL_PDU_TYPE_CAPS 0x00000003
|
||||
|
||||
#define DISP_PREVIEW 1
|
||||
|
||||
#endif /* FREERDP_CHANNEL_DISP_CLIENT_MAIN_H */
|
||||
|
||||
|
@ -29,45 +29,44 @@
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#include "dvcman.h"
|
||||
#include "drdynvc_types.h"
|
||||
#include "drdynvc_main.h"
|
||||
|
||||
static int drdynvc_write_variable_uint(wStream* stream, UINT32 val)
|
||||
static int drdynvc_write_variable_uint(wStream* s, UINT32 val)
|
||||
{
|
||||
int cb;
|
||||
|
||||
if (val <= 0xFF)
|
||||
{
|
||||
cb = 0;
|
||||
Stream_Write_UINT8(stream, val);
|
||||
Stream_Write_UINT8(s, val);
|
||||
}
|
||||
else if (val <= 0xFFFF)
|
||||
{
|
||||
cb = 1;
|
||||
Stream_Write_UINT16(stream, val);
|
||||
Stream_Write_UINT16(s, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
cb = 2;
|
||||
Stream_Write_UINT32(stream, val);
|
||||
Stream_Write_UINT32(s, val);
|
||||
}
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
int drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UINT32 data_size)
|
||||
int drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UINT32 dataSize)
|
||||
{
|
||||
wStream* data_out;
|
||||
UINT32 pos = 0;
|
||||
UINT32 cbChId;
|
||||
UINT32 cbLen;
|
||||
UINT32 chunk_len;
|
||||
int error;
|
||||
UINT32 chunkLength;
|
||||
int status;
|
||||
|
||||
DEBUG_DVC("ChannelId=%d size=%d", ChannelId, data_size);
|
||||
DEBUG_DVC("ChannelId=%d size=%d", ChannelId, dataSize);
|
||||
|
||||
if (drdynvc->channel_error != CHANNEL_RC_OK)
|
||||
return 1;
|
||||
@ -76,38 +75,38 @@ int drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UIN
|
||||
Stream_SetPosition(data_out, 1);
|
||||
cbChId = drdynvc_write_variable_uint(data_out, ChannelId);
|
||||
|
||||
if (data_size == 0)
|
||||
if (dataSize == 0)
|
||||
{
|
||||
pos = Stream_GetPosition(data_out);
|
||||
Stream_SetPosition(data_out, 0);
|
||||
Stream_Write_UINT8(data_out, 0x40 | cbChId);
|
||||
Stream_SetPosition(data_out, pos);
|
||||
error = svc_plugin_send((rdpSvcPlugin*) drdynvc, data_out);
|
||||
status = svc_plugin_send((rdpSvcPlugin*) drdynvc, data_out);
|
||||
}
|
||||
else if (data_size <= CHANNEL_CHUNK_LENGTH - pos)
|
||||
else if (dataSize <= CHANNEL_CHUNK_LENGTH - pos)
|
||||
{
|
||||
pos = Stream_GetPosition(data_out);
|
||||
Stream_SetPosition(data_out, 0);
|
||||
Stream_Write_UINT8(data_out, 0x30 | cbChId);
|
||||
Stream_SetPosition(data_out, pos);
|
||||
Stream_Write(data_out, data, data_size);
|
||||
error = svc_plugin_send((rdpSvcPlugin*) drdynvc, data_out);
|
||||
Stream_Write(data_out, data, dataSize);
|
||||
status = svc_plugin_send((rdpSvcPlugin*) drdynvc, data_out);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fragment the data */
|
||||
cbLen = drdynvc_write_variable_uint(data_out, data_size);
|
||||
cbLen = drdynvc_write_variable_uint(data_out, dataSize);
|
||||
pos = Stream_GetPosition(data_out);
|
||||
Stream_SetPosition(data_out, 0);
|
||||
Stream_Write_UINT8(data_out, 0x20 | cbChId | (cbLen << 2));
|
||||
Stream_SetPosition(data_out, pos);
|
||||
chunk_len = CHANNEL_CHUNK_LENGTH - pos;
|
||||
Stream_Write(data_out, data, chunk_len);
|
||||
data += chunk_len;
|
||||
data_size -= chunk_len;
|
||||
error = svc_plugin_send((rdpSvcPlugin*) drdynvc, data_out);
|
||||
chunkLength = CHANNEL_CHUNK_LENGTH - pos;
|
||||
Stream_Write(data_out, data, chunkLength);
|
||||
data += chunkLength;
|
||||
dataSize -= chunkLength;
|
||||
status = svc_plugin_send((rdpSvcPlugin*) drdynvc, data_out);
|
||||
|
||||
while (error == CHANNEL_RC_OK && data_size > 0)
|
||||
while (status == CHANNEL_RC_OK && dataSize > 0)
|
||||
{
|
||||
data_out = Stream_New(NULL, CHANNEL_CHUNK_LENGTH);
|
||||
Stream_SetPosition(data_out, 1);
|
||||
@ -118,20 +117,20 @@ int drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UIN
|
||||
Stream_Write_UINT8(data_out, 0x30 | cbChId);
|
||||
Stream_SetPosition(data_out, pos);
|
||||
|
||||
chunk_len = data_size;
|
||||
if (chunk_len > CHANNEL_CHUNK_LENGTH - pos)
|
||||
chunk_len = CHANNEL_CHUNK_LENGTH - pos;
|
||||
Stream_Write(data_out, data, chunk_len);
|
||||
data += chunk_len;
|
||||
data_size -= chunk_len;
|
||||
error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
|
||||
chunkLength = dataSize;
|
||||
if (chunkLength > CHANNEL_CHUNK_LENGTH - pos)
|
||||
chunkLength = CHANNEL_CHUNK_LENGTH - pos;
|
||||
Stream_Write(data_out, data, chunkLength);
|
||||
data += chunkLength;
|
||||
dataSize -= chunkLength;
|
||||
status = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out);
|
||||
}
|
||||
}
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
if (status != CHANNEL_RC_OK)
|
||||
{
|
||||
drdynvc->channel_error = error;
|
||||
DEBUG_WARN("VirtualChannelWrite failed %d", error);
|
||||
drdynvc->channel_error = status;
|
||||
DEBUG_WARN("VirtualChannelWrite failed %d", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -140,25 +139,45 @@ int drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UIN
|
||||
|
||||
int drdynvc_push_event(drdynvcPlugin* drdynvc, wMessage* event)
|
||||
{
|
||||
int error;
|
||||
int status;
|
||||
|
||||
error = svc_plugin_send_event((rdpSvcPlugin*) drdynvc, event);
|
||||
status = svc_plugin_send_event((rdpSvcPlugin*) drdynvc, event);
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
if (status != CHANNEL_RC_OK)
|
||||
{
|
||||
DEBUG_WARN("pVirtualChannelEventPush failed %d", error);
|
||||
DEBUG_WARN("pVirtualChannelEventPush failed %d", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int drdynvc_send_capability_response(drdynvcPlugin* drdynvc)
|
||||
{
|
||||
int status;
|
||||
wStream* s;
|
||||
|
||||
s = Stream_New(NULL, 4);
|
||||
Stream_Write_UINT16(s, 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */
|
||||
Stream_Write_UINT16(s, drdynvc->version);
|
||||
|
||||
status = svc_plugin_send((rdpSvcPlugin*) drdynvc, s);
|
||||
|
||||
if (status != CHANNEL_RC_OK)
|
||||
{
|
||||
DEBUG_WARN("VirtualChannelWrite failed %d", status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s)
|
||||
{
|
||||
wStream* data_out;
|
||||
int error;
|
||||
int status;
|
||||
|
||||
DEBUG_DVC("Sp=%d cbChId=%d", Sp, cbChId);
|
||||
|
||||
Stream_Seek(s, 1); /* pad */
|
||||
Stream_Read_UINT16(s, drdynvc->version);
|
||||
|
||||
@ -173,38 +192,31 @@ static int drdynvc_process_capability_request(drdynvcPlugin* drdynvc, int Sp, in
|
||||
Stream_Read_UINT16(s, drdynvc->PriorityCharge3);
|
||||
}
|
||||
|
||||
data_out = Stream_New(NULL, 4);
|
||||
Stream_Write_UINT16(data_out, 0x0050); /* Cmd+Sp+cbChId+Pad. Note: MSTSC sends 0x005c */
|
||||
Stream_Write_UINT16(data_out, drdynvc->version);
|
||||
error = svc_plugin_send((rdpSvcPlugin*) drdynvc, data_out);
|
||||
status = drdynvc_send_capability_response(drdynvc);
|
||||
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
DEBUG_WARN("VirtualChannelWrite failed %d", error);
|
||||
return 1;
|
||||
}
|
||||
drdynvc->channel_error = status;
|
||||
|
||||
drdynvc->channel_error = error;
|
||||
drdynvc->state = DRDYNVC_STATE_READY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT32 drdynvc_read_variable_uint(wStream* stream, int cbLen)
|
||||
static UINT32 drdynvc_read_variable_uint(wStream* s, int cbLen)
|
||||
{
|
||||
UINT32 val;
|
||||
|
||||
switch (cbLen)
|
||||
{
|
||||
case 0:
|
||||
Stream_Read_UINT8(stream, val);
|
||||
Stream_Read_UINT8(s, val);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
Stream_Read_UINT16(stream, val);
|
||||
Stream_Read_UINT16(s, val);
|
||||
break;
|
||||
|
||||
default:
|
||||
Stream_Read_UINT32(stream, val);
|
||||
Stream_Read_UINT32(s, val);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -217,19 +229,33 @@ static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cb
|
||||
int status;
|
||||
UINT32 ChannelId;
|
||||
wStream* data_out;
|
||||
int channel_status;
|
||||
|
||||
if (drdynvc->state == DRDYNVC_STATE_CAPABILITIES)
|
||||
{
|
||||
/**
|
||||
* For some reason the server does not always send the
|
||||
* capabilities pdu as it should. When this happens,
|
||||
* send a capabilities response.
|
||||
*/
|
||||
|
||||
drdynvc->version = 3;
|
||||
drdynvc_send_capability_response(drdynvc);
|
||||
drdynvc->state = DRDYNVC_STATE_READY;
|
||||
}
|
||||
|
||||
ChannelId = drdynvc_read_variable_uint(s, cbChId);
|
||||
pos = Stream_GetPosition(s);
|
||||
DEBUG_DVC("ChannelId=%d ChannelName=%s", ChannelId, Stream_Pointer(s));
|
||||
|
||||
status = dvcman_create_channel(drdynvc->channel_mgr, ChannelId, (char*) Stream_Pointer(s));
|
||||
channel_status = dvcman_create_channel(drdynvc->channel_mgr, ChannelId, (char*) Stream_Pointer(s));
|
||||
|
||||
data_out = Stream_New(NULL, pos + 4);
|
||||
Stream_Write_UINT8(data_out, 0x10 | cbChId);
|
||||
Stream_SetPosition(s, 1);
|
||||
Stream_Copy(data_out, s, pos - 1);
|
||||
|
||||
if (status == 0)
|
||||
if (channel_status == 0)
|
||||
{
|
||||
DEBUG_DVC("channel created");
|
||||
Stream_Write_UINT32(data_out, 0);
|
||||
@ -248,6 +274,11 @@ static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cb
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (channel_status == 0)
|
||||
{
|
||||
dvcman_open_channel(drdynvc->channel_mgr, ChannelId);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -266,8 +297,7 @@ static int drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, int cbChId
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
|
||||
Stream_Pointer(s), Stream_GetRemainingLength(s));
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId, s);
|
||||
}
|
||||
|
||||
static int drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s)
|
||||
@ -277,8 +307,7 @@ static int drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStr
|
||||
ChannelId = drdynvc_read_variable_uint(s, cbChId);
|
||||
DEBUG_DVC("ChannelId=%d", ChannelId);
|
||||
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
|
||||
Stream_Pointer(s), Stream_GetRemainingLength(s));
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId, s);
|
||||
}
|
||||
|
||||
static int drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s)
|
||||
@ -350,8 +379,6 @@ static void drdynvc_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
||||
DEBUG_WARN("unknown drdynvc cmd 0x%x", Cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
static void drdynvc_process_connect(rdpSvcPlugin* plugin)
|
||||
@ -375,6 +402,8 @@ static void drdynvc_process_connect(rdpSvcPlugin* plugin)
|
||||
}
|
||||
|
||||
dvcman_init(drdynvc->channel_mgr);
|
||||
|
||||
drdynvc->state = DRDYNVC_STATE_CAPABILITIES;
|
||||
}
|
||||
|
||||
static void drdynvc_process_event(rdpSvcPlugin* plugin, wMessage* event)
|
||||
@ -388,8 +417,16 @@ static void drdynvc_process_terminate(rdpSvcPlugin* plugin)
|
||||
|
||||
DEBUG_DVC("terminating");
|
||||
|
||||
if (!drdynvc)
|
||||
return;
|
||||
|
||||
if (drdynvc->channel_mgr)
|
||||
{
|
||||
dvcman_free(drdynvc->channel_mgr);
|
||||
drdynvc->channel_mgr = NULL;
|
||||
}
|
||||
|
||||
svc_plugin_terminate(plugin);
|
||||
|
||||
free(drdynvc);
|
||||
}
|
||||
@ -413,8 +450,10 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||
DrdynvcClientContext* context;
|
||||
CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx;
|
||||
|
||||
_p = (drdynvcPlugin*) malloc(sizeof(drdynvcPlugin));
|
||||
ZeroMemory(_p, sizeof(drdynvcPlugin));
|
||||
_p = (drdynvcPlugin*) calloc(1, sizeof(drdynvcPlugin));
|
||||
|
||||
if (!_p)
|
||||
return FALSE;
|
||||
|
||||
_p->plugin.channel_def.options =
|
||||
CHANNEL_OPTION_INITIALIZED |
|
||||
@ -423,6 +462,8 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||
|
||||
strcpy(_p->plugin.channel_def.name, "drdynvc");
|
||||
|
||||
_p->state = DRDYNVC_STATE_INITIAL;
|
||||
|
||||
_p->plugin.connect_callback = drdynvc_process_connect;
|
||||
_p->plugin.receive_callback = drdynvc_process_receive;
|
||||
_p->plugin.event_callback = drdynvc_process_event;
|
||||
@ -433,7 +474,10 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||
if ((pEntryPointsEx->cbSize >= sizeof(CHANNEL_ENTRY_POINTS_FREERDP)) &&
|
||||
(pEntryPointsEx->MagicNumber == FREERDP_CHANNEL_MAGIC_NUMBER))
|
||||
{
|
||||
context = (DrdynvcClientContext*) malloc(sizeof(DrdynvcClientContext));
|
||||
context = (DrdynvcClientContext*) calloc(1, sizeof(DrdynvcClientContext));
|
||||
|
||||
if (!context)
|
||||
return -1;
|
||||
|
||||
context->handle = (void*) _p;
|
||||
_p->context = context;
|
||||
@ -447,3 +491,4 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,17 @@
|
||||
#include <freerdp/client/drdynvc.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
enum _DRDYNVC_STATE
|
||||
{
|
||||
DRDYNVC_STATE_INITIAL,
|
||||
DRDYNVC_STATE_CAPABILITIES,
|
||||
DRDYNVC_STATE_READY,
|
||||
DRDYNVC_STATE_OPENING_CHANNEL,
|
||||
DRDYNVC_STATE_SEND_RECEIVE,
|
||||
DRDYNVC_STATE_FINAL
|
||||
};
|
||||
typedef enum _DRDYNVC_STATE DRDYNVC_STATE;
|
||||
|
||||
#define CREATE_REQUEST_PDU 0x01
|
||||
#define DATA_FIRST_PDU 0x02
|
||||
#define DATA_PDU 0x03
|
||||
@ -38,6 +49,7 @@ struct drdynvc_plugin
|
||||
{
|
||||
rdpSvcPlugin plugin;
|
||||
|
||||
DRDYNVC_STATE state;
|
||||
DrdynvcClientContext* context;
|
||||
|
||||
int version;
|
||||
|
@ -195,8 +195,7 @@ IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
||||
{
|
||||
DVCMAN* dvcman;
|
||||
|
||||
dvcman = (DVCMAN*) malloc(sizeof(DVCMAN));
|
||||
ZeroMemory(dvcman, sizeof(DVCMAN));
|
||||
dvcman = (DVCMAN*) calloc(1, sizeof(DVCMAN));
|
||||
|
||||
dvcman->iface.CreateListener = dvcman_create_listener;
|
||||
dvcman->iface.PushEvent = dvcman_push_event;
|
||||
@ -204,6 +203,7 @@ IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
||||
dvcman->iface.GetChannelId = dvcman_get_channel_id;
|
||||
dvcman->drdynvc = plugin;
|
||||
dvcman->channels = ArrayList_New(TRUE);
|
||||
dvcman->pool = StreamPool_New(TRUE, 10);
|
||||
|
||||
return (IWTSVirtualChannelManager*) dvcman;
|
||||
}
|
||||
@ -237,6 +237,8 @@ static void dvcman_channel_free(DVCMAN_CHANNEL* channel)
|
||||
if (channel->channel_callback)
|
||||
channel->channel_callback->OnClose(channel->channel_callback);
|
||||
|
||||
DeleteCriticalSection(&(channel->lock));
|
||||
|
||||
free(channel);
|
||||
}
|
||||
|
||||
@ -278,6 +280,7 @@ void dvcman_free(IWTSVirtualChannelManager* pChannelMgr)
|
||||
pPlugin->Terminated(pPlugin);
|
||||
}
|
||||
|
||||
StreamPool_Free(dvcman->pool);
|
||||
free(dvcman);
|
||||
}
|
||||
|
||||
@ -303,9 +306,11 @@ static int dvcman_write_channel(IWTSVirtualChannel* pChannel, UINT32 cbSize, BYT
|
||||
int status;
|
||||
DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel;
|
||||
|
||||
WaitForSingleObject(channel->dvc_chan_mutex, INFINITE);
|
||||
EnterCriticalSection(&(channel->lock));
|
||||
|
||||
status = drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, pBuffer, cbSize);
|
||||
ReleaseMutex(channel->dvc_chan_mutex);
|
||||
|
||||
LeaveCriticalSection(&(channel->lock));
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -334,8 +339,10 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channel
|
||||
IWTSVirtualChannelCallback* pCallback;
|
||||
DVCMAN* dvcman = (DVCMAN*) pChannelMgr;
|
||||
|
||||
channel = (DVCMAN_CHANNEL*) malloc(sizeof(DVCMAN_CHANNEL));
|
||||
ZeroMemory(channel, sizeof(DVCMAN_CHANNEL));
|
||||
channel = (DVCMAN_CHANNEL*) calloc(1, sizeof(DVCMAN_CHANNEL));
|
||||
|
||||
if (!channel)
|
||||
return -1;
|
||||
|
||||
channel->dvcman = dvcman;
|
||||
channel->channel_id = ChannelId;
|
||||
@ -349,7 +356,8 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channel
|
||||
{
|
||||
channel->iface.Write = dvcman_write_channel;
|
||||
channel->iface.Close = dvcman_close_channel_iface;
|
||||
channel->dvc_chan_mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
InitializeCriticalSection(&(channel->lock));
|
||||
|
||||
bAccept = 1;
|
||||
pCallback = NULL;
|
||||
@ -385,6 +393,28 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channel
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dvcman_open_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId)
|
||||
{
|
||||
DVCMAN_CHANNEL* channel;
|
||||
IWTSVirtualChannelCallback* pCallback;
|
||||
|
||||
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
|
||||
|
||||
if (!channel)
|
||||
{
|
||||
DEBUG_WARN("ChannelId %d not found!", ChannelId);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (channel->status == 0)
|
||||
{
|
||||
pCallback = channel->channel_callback;
|
||||
pCallback->OnOpen(pCallback);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId)
|
||||
{
|
||||
DVCMAN_CHANNEL* channel;
|
||||
@ -402,7 +432,7 @@ int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelI
|
||||
|
||||
if (channel->dvc_data)
|
||||
{
|
||||
Stream_Free(channel->dvc_data, TRUE);
|
||||
Stream_Release(channel->dvc_data);
|
||||
channel->dvc_data = NULL;
|
||||
}
|
||||
|
||||
@ -435,17 +465,19 @@ int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UI
|
||||
}
|
||||
|
||||
if (channel->dvc_data)
|
||||
Stream_Free(channel->dvc_data, TRUE);
|
||||
Stream_Release(channel->dvc_data);
|
||||
|
||||
channel->dvc_data = Stream_New(NULL, length);
|
||||
channel->dvc_data = StreamPool_Take(channel->dvcman->pool, length);
|
||||
Stream_AddRef(channel->dvc_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BYTE* data, UINT32 data_size)
|
||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, wStream* data)
|
||||
{
|
||||
int error = 0;
|
||||
int status = 0;
|
||||
DVCMAN_CHANNEL* channel;
|
||||
UINT32 dataSize = Stream_GetRemainingLength(data);
|
||||
|
||||
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
|
||||
|
||||
@ -458,28 +490,30 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C
|
||||
if (channel->dvc_data)
|
||||
{
|
||||
/* Fragmented data */
|
||||
if (Stream_GetPosition(channel->dvc_data) + data_size > (UINT32) Stream_Capacity(channel->dvc_data))
|
||||
if (Stream_GetPosition(channel->dvc_data) + dataSize > (UINT32) Stream_Capacity(channel->dvc_data))
|
||||
{
|
||||
DEBUG_WARN("data exceeding declared length!");
|
||||
Stream_Free(channel->dvc_data, TRUE);
|
||||
Stream_Release(channel->dvc_data);
|
||||
channel->dvc_data = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Stream_Write(channel->dvc_data, data, data_size);
|
||||
Stream_Write(channel->dvc_data, Stream_Pointer(data), dataSize);
|
||||
|
||||
if (((size_t) Stream_GetPosition(channel->dvc_data)) >= Stream_Capacity(channel->dvc_data))
|
||||
{
|
||||
error = channel->channel_callback->OnDataReceived(channel->channel_callback,
|
||||
Stream_Capacity(channel->dvc_data), Stream_Buffer(channel->dvc_data));
|
||||
Stream_Free(channel->dvc_data, TRUE);
|
||||
Stream_SealLength(channel->dvc_data);
|
||||
Stream_SetPosition(channel->dvc_data, 0);
|
||||
status = channel->channel_callback->OnDataReceived(channel->channel_callback, channel->dvc_data);
|
||||
Stream_Release(channel->dvc_data);
|
||||
channel->dvc_data = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = channel->channel_callback->OnDataReceived(channel->channel_callback, data_size, data);
|
||||
status = channel->channel_callback->OnDataReceived(channel->channel_callback, data);
|
||||
}
|
||||
|
||||
return error;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <freerdp/dvc.h>
|
||||
#include <freerdp/addin.h>
|
||||
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include "drdynvc_main.h"
|
||||
@ -43,6 +44,7 @@ struct _DVCMAN
|
||||
int num_listeners;
|
||||
|
||||
wArrayList* channels;
|
||||
wStreamPool* pool;
|
||||
};
|
||||
typedef struct _DVCMAN DVCMAN;
|
||||
|
||||
@ -78,7 +80,7 @@ struct _DVCMAN_CHANNEL
|
||||
IWTSVirtualChannelCallback* channel_callback;
|
||||
|
||||
wStream* dvc_data;
|
||||
HANDLE dvc_chan_mutex;
|
||||
CRITICAL_SECTION lock;
|
||||
};
|
||||
typedef struct _DVCMAN_CHANNEL DVCMAN_CHANNEL;
|
||||
|
||||
@ -87,9 +89,10 @@ int dvcman_load_addin(IWTSVirtualChannelManager* pChannelMgr, ADDIN_ARGV* args);
|
||||
void dvcman_free(IWTSVirtualChannelManager* pChannelMgr);
|
||||
int dvcman_init(IWTSVirtualChannelManager* pChannelMgr);
|
||||
int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName);
|
||||
int dvcman_open_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId);
|
||||
int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId);
|
||||
int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, UINT32 length);
|
||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BYTE* data, UINT32 data_size);
|
||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, wStream *data);
|
||||
|
||||
void* dvcman_get_channel_interface_by_name(IWTSVirtualChannelManager* pChannelMgr, const char* ChannelName);
|
||||
|
||||
|
@ -61,10 +61,12 @@ struct _ECHO_PLUGIN
|
||||
ECHO_LISTENER_CALLBACK* listener_callback;
|
||||
};
|
||||
|
||||
static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
|
||||
static int echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||
{
|
||||
int error;
|
||||
ECHO_CHANNEL_CALLBACK* callback = (ECHO_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
BYTE *pBuffer = Stream_Pointer(data);
|
||||
UINT32 cbSize = Stream_GetRemainingLength(data);
|
||||
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
int i = 0;
|
||||
|
@ -47,13 +47,12 @@
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/collections.h>
|
||||
#include <winpr/interlocked.h>
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
|
||||
struct _PARALLEL_DEVICE
|
||||
@ -93,16 +92,14 @@ static void parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
{
|
||||
irp->IoStatus = STATUS_ACCESS_DENIED;
|
||||
parallel->id = 0;
|
||||
|
||||
DEBUG_WARN("failed to create %s: %s", parallel->path, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* all read and write operations should be non-blocking */
|
||||
if (fcntl(parallel->file, F_SETFL, O_NONBLOCK) == -1)
|
||||
DEBUG_WARN("%s fcntl %s", path, strerror(errno));
|
||||
{
|
||||
|
||||
DEBUG_SVC("%s(%d) created", parallel->path, parallel->file);
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(irp->output, parallel->id);
|
||||
@ -116,9 +113,13 @@ static void parallel_process_irp_create(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
static void parallel_process_irp_close(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
{
|
||||
if (close(parallel->file) < 0)
|
||||
DEBUG_SVC("failed to close %s(%d)", parallel->path, parallel->id);
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
DEBUG_SVC("%s(%d) closed", parallel->path, parallel->id);
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Stream_Zero(irp->output, 5); /* Padding(5) */
|
||||
|
||||
@ -145,12 +146,10 @@ static void parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("read %s(%d) failed", parallel->path, parallel->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("read %llu-%llu from %d", Offset, Offset + Length, parallel->id);
|
||||
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(irp->output, Length);
|
||||
@ -177,8 +176,6 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
Stream_Read_UINT64(irp->input, Offset);
|
||||
Stream_Seek(irp->input, 20); /* Padding */
|
||||
|
||||
DEBUG_SVC("Length %u Offset %llu", Length, Offset);
|
||||
|
||||
len = Length;
|
||||
|
||||
while (len > 0)
|
||||
@ -189,8 +186,6 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("write %s(%d) failed.", parallel->path, parallel->id);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -206,15 +201,12 @@ static void parallel_process_irp_write(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
|
||||
static void parallel_process_irp_device_control(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
{
|
||||
DEBUG_SVC("in");
|
||||
Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
static void parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
{
|
||||
DEBUG_SVC("MajorFunction %u", irp->MajorFunction);
|
||||
|
||||
switch (irp->MajorFunction)
|
||||
{
|
||||
case IRP_MJ_CREATE:
|
||||
@ -238,7 +230,6 @@ static void parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp)
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
|
||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||
irp->Complete(irp);
|
||||
break;
|
||||
@ -281,8 +272,6 @@ static void parallel_free(DEVICE* device)
|
||||
{
|
||||
PARALLEL_DEVICE* parallel = (PARALLEL_DEVICE*) device;
|
||||
|
||||
DEBUG_SVC("freeing device");
|
||||
|
||||
MessageQueue_PostQuit(parallel->queue, 0);
|
||||
WaitForSingleObject(parallel->thread, INFINITE);
|
||||
CloseHandle(parallel->thread);
|
||||
|
@ -31,7 +31,6 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
|
||||
#include "printer_main.h"
|
||||
@ -87,15 +86,12 @@ static void printer_cups_write_printjob(rdpPrintJob* printjob, BYTE* data, int s
|
||||
|
||||
fp = fopen((const char*) cups_printjob->printjob_object, "a+b");
|
||||
|
||||
if (fp == NULL)
|
||||
{
|
||||
DEBUG_WARN("failed to open file %s", (char*) cups_printjob->printjob_object);
|
||||
if (!fp)
|
||||
return;
|
||||
}
|
||||
|
||||
if (fwrite(data, 1, size, fp) < size)
|
||||
{
|
||||
DEBUG_WARN("failed to write file %s", (char*) cups_printjob->printjob_object);
|
||||
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
@ -121,7 +117,7 @@ static void printer_cups_close_printjob(rdpPrintJob* printjob)
|
||||
|
||||
if (cupsPrintFile(printjob->printer->name, (const char*) cups_printjob->printjob_object, buf, 0, NULL) == 0)
|
||||
{
|
||||
DEBUG_WARN("cupsPrintFile: %s", cupsLastErrorString());
|
||||
|
||||
}
|
||||
|
||||
unlink(cups_printjob->printjob_object);
|
||||
@ -167,20 +163,19 @@ static rdpPrintJob* printer_cups_create_printjob(rdpPrinter* printer, UINT32 id)
|
||||
|
||||
cups_printjob->printjob_object = httpConnectEncrypt(cupsServer(), ippPort(), HTTP_ENCRYPT_IF_REQUESTED);
|
||||
|
||||
if (cups_printjob->printjob_object == NULL)
|
||||
if (!cups_printjob->printjob_object)
|
||||
{
|
||||
DEBUG_WARN("httpConnectEncrypt: %s", cupsLastErrorString());
|
||||
free(cups_printjob);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printer_cups_get_printjob_name(buf, sizeof(buf));
|
||||
|
||||
cups_printjob->printjob_id = cupsCreateJob((http_t*) cups_printjob->printjob_object,
|
||||
printer->name, buf, 0, NULL);
|
||||
|
||||
if (cups_printjob->printjob_id == 0)
|
||||
if (!cups_printjob->printjob_id)
|
||||
{
|
||||
DEBUG_WARN("cupsCreateJob: %s", cupsLastErrorString());
|
||||
httpClose((http_t*) cups_printjob->printjob_object);
|
||||
free(cups_printjob);
|
||||
return NULL;
|
||||
@ -281,19 +276,15 @@ rdpPrinterDriver* printer_cups_get_driver(void)
|
||||
{
|
||||
if (cups_driver == NULL)
|
||||
{
|
||||
cups_driver = (rdpCupsPrinterDriver*) malloc(sizeof(rdpCupsPrinterDriver));
|
||||
ZeroMemory(cups_driver, sizeof(rdpCupsPrinterDriver));
|
||||
cups_driver = (rdpCupsPrinterDriver*) calloc(1, sizeof(rdpCupsPrinterDriver));
|
||||
|
||||
if (!cups_driver)
|
||||
return NULL;
|
||||
|
||||
cups_driver->driver.EnumPrinters = printer_cups_enum_printers;
|
||||
cups_driver->driver.GetPrinter = printer_cups_get_printer;
|
||||
|
||||
cups_driver->id_sequence = 1;
|
||||
|
||||
#ifdef _CUPS_API_1_4
|
||||
DEBUG_SVC("using CUPS API 1.4");
|
||||
#else
|
||||
DEBUG_SVC("using CUPS API 1.2");
|
||||
#endif
|
||||
}
|
||||
|
||||
return (rdpPrinterDriver*) cups_driver;
|
||||
|
@ -28,11 +28,10 @@
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/interlocked.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#ifdef WITH_CUPS
|
||||
#include "printer_cups.h"
|
||||
@ -69,15 +68,11 @@ static void printer_process_irp_create(PRINTER_DEVICE* printer_dev, IRP* irp)
|
||||
if (printjob)
|
||||
{
|
||||
Stream_Write_UINT32(irp->output, printjob->id); /* FileId */
|
||||
|
||||
DEBUG_SVC("printjob id: %d", printjob->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream_Write_UINT32(irp->output, 0); /* FileId */
|
||||
irp->IoStatus = STATUS_PRINT_QUEUE_FULL;
|
||||
|
||||
DEBUG_WARN("error creating print job.");
|
||||
}
|
||||
|
||||
irp->Complete(irp);
|
||||
@ -87,20 +82,16 @@ static void printer_process_irp_close(PRINTER_DEVICE* printer_dev, IRP* irp)
|
||||
{
|
||||
rdpPrintJob* printjob = NULL;
|
||||
|
||||
if (printer_dev->printer != NULL)
|
||||
if (printer_dev->printer)
|
||||
printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);
|
||||
|
||||
if (!printjob)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
|
||||
DEBUG_WARN("printjob id %d not found.", irp->FileId);
|
||||
}
|
||||
else
|
||||
{
|
||||
printjob->Close(printjob);
|
||||
|
||||
DEBUG_SVC("printjob id %d closed.", irp->FileId);
|
||||
}
|
||||
|
||||
Stream_Zero(irp->output, 4); /* Padding(4) */
|
||||
@ -125,14 +116,10 @@ static void printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("printjob id %d not found.", irp->FileId);
|
||||
}
|
||||
else
|
||||
{
|
||||
printjob->Write(printjob, Stream_Pointer(irp->input), Length);
|
||||
|
||||
DEBUG_SVC("printjob id %d written %d bytes.", irp->FileId, Length);
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(irp->output, Length);
|
||||
@ -168,7 +155,6 @@ static void printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
|
||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||
irp->Complete(irp);
|
||||
break;
|
||||
@ -267,8 +253,6 @@ void printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* pri
|
||||
CachedFieldsLen = 0;
|
||||
CachedPrinterConfigData = NULL;
|
||||
|
||||
DEBUG_SVC("Printer %s registered", printer->name);
|
||||
|
||||
Flags = 0;
|
||||
|
||||
if (printer->is_default)
|
||||
@ -332,9 +316,8 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
driver = printer_win_get_driver();
|
||||
#endif
|
||||
|
||||
if (driver == NULL)
|
||||
if (!driver)
|
||||
{
|
||||
DEBUG_WARN("no driver");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -347,10 +330,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
printer = driver->GetPrinter(driver, name);
|
||||
|
||||
if (!printer)
|
||||
{
|
||||
DEBUG_WARN("printer %s not found.", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (driver_name && driver_name[0])
|
||||
printer->driver = driver_name;
|
||||
|
@ -30,8 +30,6 @@
|
||||
#include <string.h>
|
||||
#include <winspool.h>
|
||||
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#include "printer_main.h"
|
||||
|
||||
#include "printer_win.h"
|
||||
@ -69,45 +67,44 @@ static void printer_win_get_printjob_name(char* buf, int size)
|
||||
time_t tt;
|
||||
struct tm* t;
|
||||
|
||||
DEBUG_WINPR("");
|
||||
|
||||
tt = time(NULL);
|
||||
t = localtime(&tt);
|
||||
snprintf(buf, size - 1, "FreeRDP Print Job %d%02d%02d%02d%02d%02d",
|
||||
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
||||
t->tm_hour, t->tm_min, t->tm_sec);
|
||||
|
||||
DEBUG_WINPR("buf: %s", buf);
|
||||
|
||||
}
|
||||
|
||||
static void printer_win_write_printjob(rdpPrintJob* printjob, BYTE* data, int size)
|
||||
{
|
||||
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
|
||||
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
|
||||
|
||||
LPVOID pBuf = data;
|
||||
DWORD cbBuf = size;
|
||||
DWORD pcWritten;
|
||||
|
||||
if( ! WritePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten ) )
|
||||
DEBUG_WINPR("WritePrinter failed");
|
||||
;
|
||||
|
||||
if(!WritePrinter(((rdpWinPrinter*)printjob->printer)->hPrinter, pBuf, cbBuf, &pcWritten))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void printer_win_close_printjob(rdpPrintJob* printjob)
|
||||
{
|
||||
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*)printjob;
|
||||
rdpWinPrintJob* win_printjob = (rdpWinPrintJob*) printjob;
|
||||
|
||||
DEBUG_WINPR("");
|
||||
if (!EndPagePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
|
||||
{
|
||||
|
||||
if ( ! EndPagePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) )
|
||||
DEBUG_WINPR("EndPagePrinter failed");;
|
||||
if ( ! ClosePrinter( ((rdpWinPrinter*)printjob->printer)->hPrinter ) )
|
||||
DEBUG_WINPR("ClosePrinter failed");;
|
||||
}
|
||||
|
||||
((rdpWinPrinter*)printjob->printer)->printjob = NULL;
|
||||
free(win_printjob) ;
|
||||
if (!ClosePrinter(((rdpWinPrinter*) printjob->printer)->hPrinter))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
((rdpWinPrinter*) printjob->printer)->printjob = NULL;
|
||||
|
||||
free(win_printjob);
|
||||
}
|
||||
|
||||
static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
|
||||
@ -115,13 +112,10 @@ static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
|
||||
rdpWinPrinter* win_printer = (rdpWinPrinter*)printer;
|
||||
rdpWinPrintJob* win_printjob;
|
||||
|
||||
DEBUG_WINPR("");
|
||||
|
||||
if (win_printer->printjob != NULL)
|
||||
return NULL;
|
||||
|
||||
win_printjob = (rdpWinPrintJob*) malloc(sizeof(rdpWinPrintJob));
|
||||
ZeroMemory(win_printjob, sizeof(rdpWinPrintJob));
|
||||
win_printjob = (rdpWinPrintJob*) calloc(1, sizeof(rdpWinPrintJob));
|
||||
|
||||
win_printjob->printjob.id = id;
|
||||
win_printjob->printjob.printer = printer;
|
||||
@ -132,10 +126,14 @@ static rdpPrintJob* printer_win_create_printjob(rdpPrinter* printer, UINT32 id)
|
||||
win_printjob->handle = StartDocPrinter(win_printer->hPrinter, 1, (LPBYTE) &(win_printjob->di));
|
||||
|
||||
if (!win_printjob->handle)
|
||||
DEBUG_WINPR("StartDocPrinter failed");
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (!StartPagePrinter(win_printer->hPrinter))
|
||||
DEBUG_WINPR("ClosePrinter failed");
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
win_printjob->printjob.Write = printer_win_write_printjob;
|
||||
win_printjob->printjob.Close = printer_win_close_printjob;
|
||||
@ -149,9 +147,7 @@ static rdpPrintJob* printer_win_find_printjob(rdpPrinter* printer, UINT32 id)
|
||||
{
|
||||
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
|
||||
|
||||
DEBUG_WINPR("");
|
||||
|
||||
if (win_printer->printjob == NULL)
|
||||
if (!win_printer->printjob)
|
||||
return NULL;
|
||||
|
||||
if (win_printer->printjob->printjob.id != id)
|
||||
@ -164,8 +160,6 @@ static void printer_win_free_printer(rdpPrinter* printer)
|
||||
{
|
||||
rdpWinPrinter* win_printer = (rdpWinPrinter*) printer;
|
||||
|
||||
DEBUG_WINPR("");
|
||||
|
||||
if (win_printer->printjob)
|
||||
win_printer->printjob->printjob.Close((rdpPrintJob*) win_printer->printjob);
|
||||
|
||||
@ -180,10 +174,8 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, cons
|
||||
DWORD needed;
|
||||
PRINTER_INFO_2 *prninfo=NULL;
|
||||
size_t charsConverted;
|
||||
DEBUG_WINPR("");
|
||||
|
||||
win_printer = (rdpWinPrinter*) malloc(sizeof(rdpWinPrinter));
|
||||
ZeroMemory(win_printer, sizeof(rdpWinPrinter));
|
||||
win_printer = (rdpWinPrinter*) calloc(1, sizeof(rdpWinPrinter));
|
||||
|
||||
win_printer->printer.id = win_driver->id_sequence++;
|
||||
win_printer->printer.name = _strdup(name);
|
||||
@ -195,7 +187,6 @@ static rdpPrinter* printer_win_new_printer(rdpWinPrinterDriver* win_driver, cons
|
||||
|
||||
swprintf(wname, 256, L"%hs", name);
|
||||
OpenPrinter(wname, &(win_printer->hPrinter), NULL);
|
||||
DEBUG_WINPR("handle: 0x%08X", win_printer->hPrinter);
|
||||
|
||||
GetPrinter(win_printer->hPrinter, 2, (LPBYTE) prninfo, 0, &needed);
|
||||
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
|
||||
@ -216,8 +207,6 @@ static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
|
||||
size_t charsConverted;
|
||||
PRINTER_INFO_2* prninfo = NULL;
|
||||
DWORD needed, returned;
|
||||
|
||||
DEBUG_WINPR("");
|
||||
|
||||
/* find required size for the buffer */
|
||||
EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, NULL, 0, &needed, &returned);
|
||||
@ -227,19 +216,16 @@ static rdpPrinter** printer_win_enum_printers(rdpPrinterDriver* driver)
|
||||
prninfo = (PRINTER_INFO_2*) GlobalAlloc(GPTR,needed);
|
||||
|
||||
/* call again */
|
||||
if ( !EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned) )
|
||||
if (!EnumPrinters(PRINTER_ENUM_LOCAL|PRINTER_ENUM_CONNECTIONS, NULL, 2, (LPBYTE) prninfo, needed, &needed, &returned))
|
||||
{
|
||||
DEBUG_WINPR("EnumPrinters failed");
|
||||
} ; /* ERROR... */
|
||||
|
||||
DEBUG_WINPR("printers found: %d", returned);
|
||||
}
|
||||
|
||||
printers = (rdpPrinter**) malloc(sizeof(rdpPrinter*) * (returned + 1));
|
||||
ZeroMemory(printers, sizeof(rdpPrinter*) * (returned + 1));
|
||||
printers = (rdpPrinter**) calloc((returned + 1), sizeof(rdpPrinter*));
|
||||
|
||||
num_printers = 0;
|
||||
|
||||
for (i = 0; i < (int)returned; i++)
|
||||
for (i = 0; i < (int) returned; i++)
|
||||
{
|
||||
wcstombs_s(&charsConverted, pname, 1000, prninfo[i].pPrinterName, _TRUNCATE);
|
||||
printers[num_printers++] = printer_win_new_printer((rdpWinPrinterDriver*)driver,
|
||||
@ -254,8 +240,6 @@ static rdpPrinter* printer_win_get_printer(rdpPrinterDriver* driver, const char*
|
||||
{
|
||||
rdpWinPrinterDriver* win_driver = (rdpWinPrinterDriver*)driver;
|
||||
rdpPrinter *myPrinter = NULL;
|
||||
|
||||
DEBUG_WINPR("printer %s", name);
|
||||
|
||||
myPrinter = printer_win_new_printer(win_driver, name, L"", win_driver->id_sequence == 1 ? TRUE : FALSE);
|
||||
|
||||
@ -266,12 +250,9 @@ static rdpWinPrinterDriver* win_driver = NULL;
|
||||
|
||||
rdpPrinterDriver* printer_win_get_driver(void)
|
||||
{
|
||||
DEBUG_WINPR("");
|
||||
|
||||
if (win_driver == NULL)
|
||||
if (!win_driver)
|
||||
{
|
||||
win_driver = (rdpWinPrinterDriver*) malloc(sizeof(rdpWinPrinterDriver));
|
||||
ZeroMemory(win_driver, sizeof(rdpWinPrinterDriver));
|
||||
win_driver = (rdpWinPrinterDriver*) calloc(1, sizeof(rdpWinPrinterDriver));
|
||||
|
||||
win_driver->driver.EnumPrinters = printer_win_enum_printers;
|
||||
win_driver->driver.GetPrinter = printer_win_get_printer;
|
||||
|
@ -31,7 +31,6 @@
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/utils/rail.h>
|
||||
#include <freerdp/rail.h>
|
||||
|
||||
@ -95,13 +94,13 @@ static void rail_process_terminate(rdpSvcPlugin* plugin)
|
||||
railPlugin* rail = (railPlugin*) plugin;
|
||||
|
||||
WLog_Print(rail->log, WLOG_DEBUG, "Terminate");
|
||||
svc_plugin_terminate(plugin);
|
||||
}
|
||||
|
||||
static void rail_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
||||
{
|
||||
railPlugin* rail = (railPlugin*) plugin;
|
||||
rail_order_recv(rail, s);
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
static void rail_process_addin_args(rdpRailOrder* railOrder, rdpSettings* settings)
|
||||
@ -507,8 +506,7 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||
RailClientContext* context;
|
||||
CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx;
|
||||
|
||||
rail = (railPlugin*) malloc(sizeof(railPlugin));
|
||||
ZeroMemory(rail, sizeof(railPlugin));
|
||||
rail = (railPlugin*) calloc(1, sizeof(railPlugin));
|
||||
|
||||
rail->plugin.channel_def.options =
|
||||
CHANNEL_OPTION_INITIALIZED |
|
||||
|
@ -34,6 +34,7 @@ static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("RdpdrServerSendAnnounceRequest\n");
|
||||
|
||||
@ -51,7 +52,7 @@ static int rdpdr_server_send_announce_request(RdpdrServerContext* context)
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
@ -295,6 +296,7 @@ static int rdpdr_server_send_core_capability_request(RdpdrServerContext* context
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
UINT16 numCapabilities;
|
||||
ULONG written;
|
||||
|
||||
printf("RdpdrServerSendCoreCapabilityRequest\n");
|
||||
|
||||
@ -319,7 +321,7 @@ static int rdpdr_server_send_core_capability_request(RdpdrServerContext* context
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
@ -376,6 +378,7 @@ static int rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("RdpdrServerSendClientIdConfirm\n");
|
||||
|
||||
@ -393,7 +396,7 @@ static int rdpdr_server_send_client_id_confirm(RdpdrServerContext* context)
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
@ -457,6 +460,7 @@ static int rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
|
||||
wStream* s;
|
||||
BOOL status;
|
||||
RDPDR_HEADER header;
|
||||
ULONG written;
|
||||
|
||||
printf("%s\n", __FUNCTION__);
|
||||
|
||||
@ -470,7 +474,7 @@ static int rdpdr_server_send_user_logged_on(RdpdrServerContext* context)
|
||||
|
||||
Stream_SealLength(s);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_Length(s), &written);
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
|
||||
|
@ -434,17 +434,12 @@ int rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
|
||||
static int rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||
{
|
||||
wStream* s;
|
||||
int status = 0;
|
||||
RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
s = Stream_New(pBuffer, cbSize);
|
||||
|
||||
status = rdpei_recv_pdu(callback, s);
|
||||
|
||||
Stream_Free(s, FALSE);
|
||||
status = rdpei_recv_pdu(callback, data);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ define_channel_client("rdpgfx")
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
rdpgfx_main.c
|
||||
rdpgfx_main.h
|
||||
rdpgfx_codec.c
|
||||
rdpgfx_codec.h
|
||||
rdpgfx_common.c
|
||||
rdpgfx_common.h)
|
||||
|
||||
@ -32,7 +34,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE freerdp
|
||||
MODULES freerdp-common freerdp-utils)
|
||||
MODULES freerdp-common freerdp-codec freerdp-utils)
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
|
111
channels/rdpgfx/client/rdpgfx_codec.c
Normal file
111
channels/rdpgfx/client/rdpgfx_codec.c
Normal file
@ -0,0 +1,111 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Graphics Pipeline Extension
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "rdpgfx_codec.h"
|
||||
|
||||
int rdpgfx_decode_uncompressed(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_decode_remotefx(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
fprintf(stderr, "RdpGfxDecodeRemoteFx\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_decode_clear(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_decode_planar(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_decode_h264(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_decode_alpha(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_decode_progressive(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_decode_progressive_v2(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status;
|
||||
|
||||
switch (cmd->codecId)
|
||||
{
|
||||
case RDPGFX_CODECID_UNCOMPRESSED:
|
||||
status = rdpgfx_decode_uncompressed(gfx, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_CAVIDEO:
|
||||
status = rdpgfx_decode_remotefx(gfx, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_CLEARCODEC:
|
||||
status = rdpgfx_decode_clear(gfx, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_PLANAR:
|
||||
status = rdpgfx_decode_planar(gfx, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_H264:
|
||||
status = rdpgfx_decode_h264(gfx, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_ALPHA:
|
||||
status = rdpgfx_decode_alpha(gfx, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_CAPROGRESSIVE:
|
||||
status = rdpgfx_decode_progressive(gfx, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
|
||||
status = rdpgfx_decode_progressive_v2(gfx, cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Sample Virtual Channel
|
||||
* Graphics Pipeline Extension
|
||||
*
|
||||
* Copyright 2012 Jay Sorg
|
||||
* Copyright 2010-2012 Vic Lee
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -18,9 +17,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __SAMPLE_MAIN_H
|
||||
#define __SAMPLE_MAIN_H
|
||||
#ifndef FREERDP_CHANNEL_RDPGFX_CLIENT_CODEC_H
|
||||
#define FREERDP_CHANNEL_RDPGFX_CLIENT_CODEC_H
|
||||
|
||||
typedef struct sample_plugin samplePlugin;
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#endif /* __SAMPLE_MAIN_H */
|
||||
#include <freerdp/channels/rdpgfx.h>
|
||||
|
||||
#include "rdpgfx_main.h"
|
||||
|
||||
int rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd);
|
||||
|
||||
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_CODEC_H */
|
@ -26,12 +26,89 @@
|
||||
|
||||
#include "rdpgfx_common.h"
|
||||
|
||||
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* point16)
|
||||
const char* RDPGFX_CMDID_STRINGS[] =
|
||||
{
|
||||
Stream_Read_UINT16(s, point16->x); /* x (2 bytes) */
|
||||
Stream_Read_UINT16(s, point16->y); /* y (2 bytes) */
|
||||
"RDPGFX_CMDID_UNUSED_0000",
|
||||
"RDPGFX_CMDID_WIRETOSURFACE_1",
|
||||
"RDPGFX_CMDID_WIRETOSURFACE_2",
|
||||
"RDPGFX_CMDID_DELETEENCODINGCONTEXT",
|
||||
"RDPGFX_CMDID_SOLIDFILL",
|
||||
"RDPGFX_CMDID_SURFACETOSURFACE",
|
||||
"RDPGFX_CMDID_SURFACETOCACHE",
|
||||
"RDPGFX_CMDID_CACHETOSURFACE",
|
||||
"RDPGFX_CMDID_EVICTCACHEENTRY",
|
||||
"RDPGFX_CMDID_CREATESURFACE",
|
||||
"RDPGFX_CMDID_DELETESURFACE",
|
||||
"RDPGFX_CMDID_STARTFRAME",
|
||||
"RDPGFX_CMDID_ENDFRAME",
|
||||
"RDPGFX_CMDID_FRAMEACKNOWLEDGE",
|
||||
"RDPGFX_CMDID_RESETGRAPHICS",
|
||||
"RDPGFX_CMDID_MAPSURFACETOOUTPUT",
|
||||
"RDPGFX_CMDID_CACHEIMPORTOFFER",
|
||||
"RDPGFX_CMDID_CACHEIMPORTREPLY",
|
||||
"RDPGFX_CMDID_CAPSADVERTISE",
|
||||
"RDPGFX_CMDID_CAPSCONFIRM",
|
||||
"RDPGFX_CMDID_UNUSED_0014",
|
||||
"RDPGFX_CMDID_MAPSURFACETOWINDOW"
|
||||
};
|
||||
|
||||
return 0;
|
||||
const char* rdpgfx_get_cmd_id_string(UINT16 cmdId)
|
||||
{
|
||||
if (cmdId <= RDPGFX_CMDID_MAPSURFACETOWINDOW)
|
||||
return RDPGFX_CMDID_STRINGS[cmdId];
|
||||
else
|
||||
return "RDPGFX_CMDID_UNKNOWN";
|
||||
}
|
||||
|
||||
const char* rdpgfx_get_codec_id_string(UINT16 codecId)
|
||||
{
|
||||
switch (codecId)
|
||||
{
|
||||
case RDPGFX_CODECID_UNCOMPRESSED:
|
||||
return "RDPGFX_CODECID_UNCOMPRESSED";
|
||||
case RDPGFX_CODECID_CAVIDEO:
|
||||
return "RDPGFX_CODECID_CAVIDEO";
|
||||
case RDPGFX_CODECID_CLEARCODEC:
|
||||
return "RDPGFX_CODECID_CLEARCODEC";
|
||||
case RDPGFX_CODECID_PLANAR:
|
||||
return "RDPGFX_CODECID_PLANAR";
|
||||
case RDPGFX_CODECID_H264:
|
||||
return "RDPGFX_CODECID_H264";
|
||||
case RDPGFX_CODECID_ALPHA:
|
||||
return "RDPGFX_CODECID_ALPHA";
|
||||
case RDPGFX_CODECID_CAPROGRESSIVE:
|
||||
return "RDPGFX_CODECID_CAPROGRESSIVE";
|
||||
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
|
||||
return "RDPGFX_CODECID_CAPROGRESSIVE_V2";
|
||||
}
|
||||
|
||||
return "RDPGFX_CODECID_UNKNOWN";
|
||||
}
|
||||
|
||||
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
|
||||
{
|
||||
Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
|
||||
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
|
||||
Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header)
|
||||
{
|
||||
Stream_Write_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
|
||||
Stream_Write_UINT16(s, header->flags); /* flags (2 bytes) */
|
||||
Stream_Write_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16)
|
||||
{
|
||||
Stream_Read_UINT16(s, pt16->x); /* x (2 bytes) */
|
||||
Stream_Read_UINT16(s, pt16->y); /* y (2 bytes) */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16)
|
||||
@ -39,7 +116,7 @@ int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16)
|
||||
Stream_Write_UINT16(s, point16->x); /* x (2 bytes) */
|
||||
Stream_Write_UINT16(s, point16->y); /* y (2 bytes) */
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
||||
@ -49,7 +126,7 @@ int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
||||
Stream_Read_UINT16(s, rect16->right); /* right (2 bytes) */
|
||||
Stream_Read_UINT16(s, rect16->bottom); /* bottom (2 bytes) */
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
||||
@ -59,7 +136,7 @@ int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16)
|
||||
Stream_Write_UINT16(s, rect16->right); /* right (2 bytes) */
|
||||
Stream_Write_UINT16(s, rect16->bottom); /* bottom (2 bytes) */
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32)
|
||||
@ -69,7 +146,7 @@ int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32)
|
||||
Stream_Read_UINT8(s, color32->R); /* R (1 byte) */
|
||||
Stream_Read_UINT8(s, color32->XA); /* XA (1 byte) */
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32)
|
||||
@ -79,23 +156,5 @@ int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32)
|
||||
Stream_Write_UINT8(s, color32->R); /* R (1 byte) */
|
||||
Stream_Write_UINT8(s, color32->XA); /* XA (1 byte) */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
|
||||
{
|
||||
Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
|
||||
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
|
||||
Stream_Read_UINT16(s, header->pduLength); /* pduLength (4 bytes) */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header)
|
||||
{
|
||||
Stream_Write_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
|
||||
Stream_Write_UINT16(s, header->flags); /* flags (2 bytes) */
|
||||
Stream_Write_UINT16(s, header->pduLength); /* pduLength (4 bytes) */
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -25,14 +25,20 @@
|
||||
|
||||
#include <freerdp/channels/rdpgfx.h>
|
||||
|
||||
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* point16);
|
||||
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16);
|
||||
int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
||||
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
||||
int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32);
|
||||
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32);
|
||||
const char* rdpgfx_get_cmd_id_string(UINT16 cmdId);
|
||||
const char* rdpgfx_get_codec_id_string(UINT16 codecId);
|
||||
|
||||
int rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header);
|
||||
int rdpgfx_write_header(wStream* s, RDPGFX_HEADER* header);
|
||||
|
||||
int rdpgfx_read_point16(wStream* s, RDPGFX_POINT16* pt16);
|
||||
int rdpgfx_write_point16(wStream* s, RDPGFX_POINT16* point16);
|
||||
|
||||
int rdpgfx_read_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
||||
int rdpgfx_write_rect16(wStream* s, RDPGFX_RECT16* rect16);
|
||||
|
||||
int rdpgfx_read_color32(wStream* s, RDPGFX_COLOR32* color32);
|
||||
int rdpgfx_write_color32(wStream* s, RDPGFX_COLOR32* color32);
|
||||
|
||||
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_COMMON_H */
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Graphics Pipeline Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2013-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -20,17 +20,60 @@
|
||||
#ifndef FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H
|
||||
#define FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <freerdp/dvc.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/addin.h>
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include <freerdp/client/rdpgfx.h>
|
||||
|
||||
#include <freerdp/codec/zgfx.h>
|
||||
|
||||
struct _RDPGFX_CHANNEL_CALLBACK
|
||||
{
|
||||
IWTSVirtualChannelCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
IWTSVirtualChannel* channel;
|
||||
};
|
||||
typedef struct _RDPGFX_CHANNEL_CALLBACK RDPGFX_CHANNEL_CALLBACK;
|
||||
|
||||
struct _RDPGFX_LISTENER_CALLBACK
|
||||
{
|
||||
IWTSListenerCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
RDPGFX_CHANNEL_CALLBACK* channel_callback;
|
||||
};
|
||||
typedef struct _RDPGFX_LISTENER_CALLBACK RDPGFX_LISTENER_CALLBACK;
|
||||
|
||||
struct _RDPGFX_PLUGIN
|
||||
{
|
||||
IWTSPlugin iface;
|
||||
|
||||
IWTSListener* listener;
|
||||
RDPGFX_LISTENER_CALLBACK* listener_callback;
|
||||
|
||||
wLog* log;
|
||||
|
||||
BOOL ThinClient;
|
||||
BOOL SmallCache;
|
||||
BOOL H264;
|
||||
|
||||
ZGFX_CONTEXT* zgfx;
|
||||
UINT32 UnacknowledgedFrames;
|
||||
UINT32 TotalDecodedFrames;
|
||||
|
||||
wHashTable* SurfaceTable;
|
||||
|
||||
UINT16 MaxCacheSlot;
|
||||
void* CacheSlots[25600];
|
||||
};
|
||||
typedef struct _RDPGFX_PLUGIN RDPGFX_PLUGIN;
|
||||
|
||||
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H */
|
||||
|
||||
|
@ -20,12 +20,11 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
@ -37,66 +36,66 @@
|
||||
|
||||
typedef struct rdpsnd_ios_plugin
|
||||
{
|
||||
rdpsndDevicePlugin device;
|
||||
AudioComponentInstance audio_unit;
|
||||
TPCircularBuffer buffer;
|
||||
BOOL is_opened;
|
||||
BOOL is_playing;
|
||||
rdpsndDevicePlugin device;
|
||||
AudioComponentInstance audio_unit;
|
||||
TPCircularBuffer buffer;
|
||||
BOOL is_opened;
|
||||
BOOL is_playing;
|
||||
} rdpsndIOSPlugin;
|
||||
|
||||
#define THIS(__ptr) ((rdpsndIOSPlugin*)__ptr)
|
||||
|
||||
static OSStatus rdpsnd_ios_render_cb(
|
||||
void *inRefCon,
|
||||
AudioUnitRenderActionFlags __unused *ioActionFlags,
|
||||
const AudioTimeStamp __unused *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 __unused inNumberFrames,
|
||||
AudioBufferList *ioData
|
||||
void *inRefCon,
|
||||
AudioUnitRenderActionFlags __unused *ioActionFlags,
|
||||
const AudioTimeStamp __unused *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 __unused inNumberFrames,
|
||||
AudioBufferList *ioData
|
||||
)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (inBusNumber != 0)
|
||||
{
|
||||
return noErr;
|
||||
}
|
||||
|
||||
rdpsndIOSPlugin *p = THIS(inRefCon);
|
||||
|
||||
for (i = 0; i < ioData->mNumberBuffers; i++)
|
||||
{
|
||||
AudioBuffer* target_buffer = &ioData->mBuffers[i];
|
||||
|
||||
int32_t available_bytes = 0;
|
||||
const void *buffer = TPCircularBufferTail(&p->buffer, &available_bytes);
|
||||
if (buffer != NULL && available_bytes > 0)
|
||||
{
|
||||
const int bytes_to_copy = MIN((int32_t)target_buffer->mDataByteSize, available_bytes);
|
||||
|
||||
memcpy(target_buffer->mData, buffer, bytes_to_copy);
|
||||
target_buffer->mDataByteSize = bytes_to_copy;
|
||||
|
||||
TPCircularBufferConsume(&p->buffer, bytes_to_copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
target_buffer->mDataByteSize = 0;
|
||||
AudioOutputUnitStop(p->audio_unit);
|
||||
p->is_playing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return noErr;
|
||||
unsigned int i;
|
||||
|
||||
if (inBusNumber != 0)
|
||||
{
|
||||
return noErr;
|
||||
}
|
||||
|
||||
rdpsndIOSPlugin *p = THIS(inRefCon);
|
||||
|
||||
for (i = 0; i < ioData->mNumberBuffers; i++)
|
||||
{
|
||||
AudioBuffer* target_buffer = &ioData->mBuffers[i];
|
||||
|
||||
int32_t available_bytes = 0;
|
||||
const void *buffer = TPCircularBufferTail(&p->buffer, &available_bytes);
|
||||
if (buffer != NULL && available_bytes > 0)
|
||||
{
|
||||
const int bytes_to_copy = MIN((int32_t)target_buffer->mDataByteSize, available_bytes);
|
||||
|
||||
memcpy(target_buffer->mData, buffer, bytes_to_copy);
|
||||
target_buffer->mDataByteSize = bytes_to_copy;
|
||||
|
||||
TPCircularBufferConsume(&p->buffer, bytes_to_copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
target_buffer->mDataByteSize = 0;
|
||||
AudioOutputUnitStop(p->audio_unit);
|
||||
p->is_playing = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_ios_format_supported(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* format)
|
||||
{
|
||||
if (format->wFormatTag == WAVE_FORMAT_PCM)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
if (format->wFormatTag == WAVE_FORMAT_PCM)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rdpsnd_ios_set_format(rdpsndDevicePlugin* __unused device, AUDIO_FORMAT* __unused format, int __unused latency)
|
||||
@ -109,170 +108,170 @@ static void rdpsnd_ios_set_volume(rdpsndDevicePlugin* __unused device, UINT32 __
|
||||
|
||||
static void rdpsnd_ios_start(rdpsndDevicePlugin* device)
|
||||
{
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
|
||||
/* If this device is not playing... */
|
||||
if (!p->is_playing)
|
||||
{
|
||||
/* Start the device. */
|
||||
int32_t available_bytes = 0;
|
||||
TPCircularBufferTail(&p->buffer, &available_bytes);
|
||||
if (available_bytes > 0)
|
||||
{
|
||||
p->is_playing = 1;
|
||||
AudioOutputUnitStart(p->audio_unit);
|
||||
}
|
||||
}
|
||||
/* If this device is not playing... */
|
||||
if (!p->is_playing)
|
||||
{
|
||||
/* Start the device. */
|
||||
int32_t available_bytes = 0;
|
||||
TPCircularBufferTail(&p->buffer, &available_bytes);
|
||||
if (available_bytes > 0)
|
||||
{
|
||||
p->is_playing = 1;
|
||||
AudioOutputUnitStart(p->audio_unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rdpsnd_ios_stop(rdpsndDevicePlugin* __unused device)
|
||||
{
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
|
||||
/* If the device is playing... */
|
||||
if (p->is_playing)
|
||||
{
|
||||
/* Stop the device. */
|
||||
AudioOutputUnitStop(p->audio_unit);
|
||||
p->is_playing = 0;
|
||||
/* If the device is playing... */
|
||||
if (p->is_playing)
|
||||
{
|
||||
/* Stop the device. */
|
||||
AudioOutputUnitStop(p->audio_unit);
|
||||
p->is_playing = 0;
|
||||
|
||||
/* Free all buffers. */
|
||||
TPCircularBufferClear(&p->buffer);
|
||||
}
|
||||
/* Free all buffers. */
|
||||
TPCircularBufferClear(&p->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void rdpsnd_ios_play(rdpsndDevicePlugin* device, BYTE* data, int size)
|
||||
{
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
|
||||
const BOOL ok = TPCircularBufferProduceBytes(&p->buffer, data, size);
|
||||
if (!ok)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rdpsnd_ios_start(device);
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
|
||||
const BOOL ok = TPCircularBufferProduceBytes(&p->buffer, data, size);
|
||||
if (!ok)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
rdpsnd_ios_start(device);
|
||||
}
|
||||
|
||||
static void rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int __unused latency)
|
||||
{
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
|
||||
if (p->is_opened)
|
||||
{
|
||||
return;
|
||||
}
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
|
||||
/* Find the output audio unit. */
|
||||
AudioComponentDescription desc;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
|
||||
AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc);
|
||||
if (audioComponent == NULL) return;
|
||||
if (p->is_opened)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Open the audio unit. */
|
||||
OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit);
|
||||
if (status != 0) return;
|
||||
/* Find the output audio unit. */
|
||||
AudioComponentDescription desc;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
|
||||
/* Set the format for the AudioUnit. */
|
||||
AudioStreamBasicDescription audioFormat = {0};
|
||||
audioFormat.mSampleRate = format->nSamplesPerSec;
|
||||
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
|
||||
audioFormat.mFramesPerPacket = 1; /* imminent property of the Linear PCM */
|
||||
audioFormat.mChannelsPerFrame = format->nChannels;
|
||||
audioFormat.mBitsPerChannel = format->wBitsPerSample;
|
||||
audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8;
|
||||
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
|
||||
|
||||
status = AudioUnitSetProperty(
|
||||
p->audio_unit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&audioFormat,
|
||||
sizeof(audioFormat));
|
||||
if (status != 0)
|
||||
{
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up the AudioUnit callback. */
|
||||
AURenderCallbackStruct callbackStruct = {0};
|
||||
callbackStruct.inputProc = rdpsnd_ios_render_cb;
|
||||
callbackStruct.inputProcRefCon = p;
|
||||
status = AudioUnitSetProperty(
|
||||
p->audio_unit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&callbackStruct,
|
||||
sizeof(callbackStruct));
|
||||
if (status != 0)
|
||||
{
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
return;
|
||||
}
|
||||
AudioComponent audioComponent = AudioComponentFindNext(NULL, &desc);
|
||||
if (audioComponent == NULL) return;
|
||||
|
||||
/* Initialize the AudioUnit. */
|
||||
status = AudioUnitInitialize(p->audio_unit);
|
||||
if (status != 0)
|
||||
{
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate the circular buffer. */
|
||||
const BOOL ok = TPCircularBufferInit(&p->buffer, CIRCULAR_BUFFER_SIZE);
|
||||
if (!ok)
|
||||
{
|
||||
AudioUnitUninitialize(p->audio_unit);
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
return;
|
||||
}
|
||||
/* Open the audio unit. */
|
||||
OSStatus status = AudioComponentInstanceNew(audioComponent, &p->audio_unit);
|
||||
if (status != 0) return;
|
||||
|
||||
p->is_opened = 1;
|
||||
/* Set the format for the AudioUnit. */
|
||||
AudioStreamBasicDescription audioFormat = {0};
|
||||
audioFormat.mSampleRate = format->nSamplesPerSec;
|
||||
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
|
||||
audioFormat.mFramesPerPacket = 1; /* imminent property of the Linear PCM */
|
||||
audioFormat.mChannelsPerFrame = format->nChannels;
|
||||
audioFormat.mBitsPerChannel = format->wBitsPerSample;
|
||||
audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8;
|
||||
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;
|
||||
|
||||
status = AudioUnitSetProperty(
|
||||
p->audio_unit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&audioFormat,
|
||||
sizeof(audioFormat));
|
||||
if (status != 0)
|
||||
{
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up the AudioUnit callback. */
|
||||
AURenderCallbackStruct callbackStruct = {0};
|
||||
callbackStruct.inputProc = rdpsnd_ios_render_cb;
|
||||
callbackStruct.inputProcRefCon = p;
|
||||
status = AudioUnitSetProperty(
|
||||
p->audio_unit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Input,
|
||||
0,
|
||||
&callbackStruct,
|
||||
sizeof(callbackStruct));
|
||||
if (status != 0)
|
||||
{
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Initialize the AudioUnit. */
|
||||
status = AudioUnitInitialize(p->audio_unit);
|
||||
if (status != 0)
|
||||
{
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate the circular buffer. */
|
||||
const BOOL ok = TPCircularBufferInit(&p->buffer, CIRCULAR_BUFFER_SIZE);
|
||||
if (!ok)
|
||||
{
|
||||
AudioUnitUninitialize(p->audio_unit);
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
p->is_opened = 1;
|
||||
}
|
||||
|
||||
static void rdpsnd_ios_close(rdpsndDevicePlugin* device)
|
||||
{
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
|
||||
/* Make sure the device is stopped. */
|
||||
rdpsnd_ios_stop(device);
|
||||
/* Make sure the device is stopped. */
|
||||
rdpsnd_ios_stop(device);
|
||||
|
||||
/* If the device is open... */
|
||||
if (p->is_opened)
|
||||
{
|
||||
/* Close the device. */
|
||||
AudioUnitUninitialize(p->audio_unit);
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
p->is_opened = 0;
|
||||
|
||||
/* Destroy the circular buffer. */
|
||||
TPCircularBufferCleanup(&p->buffer);
|
||||
}
|
||||
/* If the device is open... */
|
||||
if (p->is_opened)
|
||||
{
|
||||
/* Close the device. */
|
||||
AudioUnitUninitialize(p->audio_unit);
|
||||
AudioComponentInstanceDispose(p->audio_unit);
|
||||
p->audio_unit = NULL;
|
||||
p->is_opened = 0;
|
||||
|
||||
/* Destroy the circular buffer. */
|
||||
TPCircularBufferCleanup(&p->buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void rdpsnd_ios_free(rdpsndDevicePlugin* device)
|
||||
{
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
rdpsndIOSPlugin *p = THIS(device);
|
||||
|
||||
/* Ensure the device is closed. */
|
||||
rdpsnd_ios_close(device);
|
||||
/* Ensure the device is closed. */
|
||||
rdpsnd_ios_close(device);
|
||||
|
||||
/* Free memory associated with the device. */
|
||||
free(p);
|
||||
/* Free memory associated with the device. */
|
||||
free(p);
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
@ -281,19 +280,21 @@ static void rdpsnd_ios_free(rdpsndDevicePlugin* device)
|
||||
|
||||
int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
rdpsndIOSPlugin *p = (rdpsndIOSPlugin*)malloc(sizeof(rdpsndIOSPlugin));
|
||||
memset(p, 0, sizeof(rdpsndIOSPlugin));
|
||||
|
||||
p->device.Open = rdpsnd_ios_open;
|
||||
p->device.FormatSupported = rdpsnd_ios_format_supported;
|
||||
p->device.SetFormat = rdpsnd_ios_set_format;
|
||||
p->device.SetVolume = rdpsnd_ios_set_volume;
|
||||
p->device.Play = rdpsnd_ios_play;
|
||||
p->device.Start = rdpsnd_ios_start;
|
||||
p->device.Close = rdpsnd_ios_close;
|
||||
p->device.Free = rdpsnd_ios_free;
|
||||
|
||||
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
rdpsndIOSPlugin* p = (rdpsndIOSPlugin*) calloc(1, sizeof(rdpsndIOSPlugin));
|
||||
|
||||
if (!p)
|
||||
return -1;
|
||||
|
||||
p->device.Open = rdpsnd_ios_open;
|
||||
p->device.FormatSupported = rdpsnd_ios_format_supported;
|
||||
p->device.SetFormat = rdpsnd_ios_set_format;
|
||||
p->device.SetVolume = rdpsnd_ios_set_volume;
|
||||
p->device.Play = rdpsnd_ios_play;
|
||||
p->device.Start = rdpsnd_ios_start;
|
||||
p->device.Close = rdpsnd_ios_close;
|
||||
p->device.Free = rdpsnd_ios_free;
|
||||
|
||||
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,7 +29,6 @@
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include <AudioToolbox/AudioQueue.h>
|
||||
@ -282,23 +281,21 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
|
||||
{
|
||||
rdpsndMacPlugin* mac;
|
||||
|
||||
mac = (rdpsndMacPlugin*) malloc(sizeof(rdpsndMacPlugin));
|
||||
mac = (rdpsndMacPlugin*) calloc(1, sizeof(rdpsndMacPlugin));
|
||||
|
||||
if (mac)
|
||||
{
|
||||
ZeroMemory(mac, sizeof(rdpsndMacPlugin));
|
||||
if (!mac)
|
||||
return -1;
|
||||
|
||||
mac->device.Open = rdpsnd_mac_open;
|
||||
mac->device.FormatSupported = rdpsnd_mac_format_supported;
|
||||
mac->device.SetFormat = rdpsnd_mac_set_format;
|
||||
mac->device.SetVolume = rdpsnd_mac_set_volume;
|
||||
mac->device.Play = rdpsnd_mac_play;
|
||||
mac->device.Start = rdpsnd_mac_start;
|
||||
mac->device.Close = rdpsnd_mac_close;
|
||||
mac->device.Free = rdpsnd_mac_free;
|
||||
mac->device.Open = rdpsnd_mac_open;
|
||||
mac->device.FormatSupported = rdpsnd_mac_format_supported;
|
||||
mac->device.SetFormat = rdpsnd_mac_set_format;
|
||||
mac->device.SetVolume = rdpsnd_mac_set_volume;
|
||||
mac->device.Play = rdpsnd_mac_play;
|
||||
mac->device.Start = rdpsnd_mac_start;
|
||||
mac->device.Close = rdpsnd_mac_close;
|
||||
mac->device.Free = rdpsnd_mac_free;
|
||||
|
||||
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac);
|
||||
}
|
||||
pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -37,7 +37,6 @@
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#include "rdpsnd_main.h"
|
||||
|
||||
@ -74,18 +73,15 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd
|
||||
switch (state)
|
||||
{
|
||||
case PA_CONTEXT_READY:
|
||||
DEBUG_SVC("PA_CONTEXT_READY");
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
case PA_CONTEXT_FAILED:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
DEBUG_SVC("PA_CONTEXT_FAILED/PA_CONTEXT_TERMINATED %d", (int)state);
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_SVC("state %d", (int)state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -100,7 +96,6 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
|
||||
|
||||
if (pa_context_connect(pulse->context, NULL, 0, NULL))
|
||||
{
|
||||
DEBUG_WARN("pa_context_connect failed (%d)", pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -109,7 +104,6 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
|
||||
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_WARN("pa_threaded_mainloop_start failed (%d)", pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -122,7 +116,6 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
|
||||
|
||||
if (!PA_CONTEXT_IS_GOOD(state))
|
||||
{
|
||||
DEBUG_WARN("bad context state (%d)", pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -133,7 +126,6 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device)
|
||||
|
||||
if (state == PA_CONTEXT_READY)
|
||||
{
|
||||
DEBUG_SVC("connected");
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@ -173,18 +165,15 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata
|
||||
switch (state)
|
||||
{
|
||||
case PA_STREAM_READY:
|
||||
DEBUG_SVC("PA_STREAM_READY");
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
DEBUG_SVC("state %d", (int)state);
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_SVC("state %d", (int)state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -270,7 +259,6 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
|
||||
|
||||
if (!pulse->context || pulse->stream)
|
||||
{
|
||||
DEBUG_WARN("pulse stream has been created.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -280,7 +268,6 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
|
||||
if (pa_sample_spec_valid(&pulse->sample_spec) == 0)
|
||||
{
|
||||
pa_sample_spec_snprint(ss, sizeof(ss), &pulse->sample_spec);
|
||||
DEBUG_WARN("Invalid sample spec %s", ss);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -291,7 +278,6 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
|
||||
if (!pulse->stream)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_WARN("pa_stream_new failed (%d)", pa_context_errno(pulse->context));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -315,8 +301,6 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
|
||||
pulse->device_name, pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_WARN("pa_stream_connect_playback failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -329,8 +313,6 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
|
||||
|
||||
if (!PA_STREAM_IS_GOOD(state))
|
||||
{
|
||||
DEBUG_WARN("bad stream state (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -349,8 +331,6 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
|
||||
|
||||
pulse->gsm_context = gsm_create();
|
||||
#endif
|
||||
|
||||
DEBUG_SVC("connected");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -584,8 +564,6 @@ static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, BYTE* data, int size)
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
DEBUG_WARN("pa_stream_write failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -653,8 +631,10 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
|
||||
ADDIN_ARGV* args;
|
||||
rdpsndPulsePlugin* pulse;
|
||||
|
||||
pulse = (rdpsndPulsePlugin*) malloc(sizeof(rdpsndPulsePlugin));
|
||||
ZeroMemory(pulse, sizeof(rdpsndPulsePlugin));
|
||||
pulse = (rdpsndPulsePlugin*) calloc(1, sizeof(rdpsndPulsePlugin));
|
||||
|
||||
if (!pulse)
|
||||
return -1;
|
||||
|
||||
pulse->device.Open = rdpsnd_pulse_open;
|
||||
pulse->device.FormatSupported = rdpsnd_pulse_format_supported;
|
||||
@ -678,7 +658,6 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
|
||||
|
||||
if (!pulse->mainloop)
|
||||
{
|
||||
DEBUG_WARN("pa_threaded_mainloop_new failed");
|
||||
rdpsnd_pulse_free((rdpsndDevicePlugin*)pulse);
|
||||
return 1;
|
||||
}
|
||||
@ -687,7 +666,6 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
|
||||
|
||||
if (!pulse->context)
|
||||
{
|
||||
DEBUG_WARN("pa_context_new failed");
|
||||
rdpsnd_pulse_free((rdpsndDevicePlugin*)pulse);
|
||||
return 1;
|
||||
}
|
||||
@ -696,7 +674,6 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
|
||||
|
||||
if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse))
|
||||
{
|
||||
DEBUG_WARN("rdpsnd_pulse_connect failed");
|
||||
rdpsnd_pulse_free((rdpsndDevicePlugin*)pulse);
|
||||
return 1;
|
||||
}
|
||||
|
@ -34,7 +34,6 @@
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#include "rdpsnd_main.h"
|
||||
|
||||
@ -333,8 +332,10 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
|
||||
ADDIN_ARGV* args;
|
||||
rdpsndWinmmPlugin* winmm;
|
||||
|
||||
winmm = (rdpsndWinmmPlugin*) malloc(sizeof(rdpsndWinmmPlugin));
|
||||
ZeroMemory(winmm, sizeof(rdpsndWinmmPlugin));
|
||||
winmm = (rdpsndWinmmPlugin*) calloc(1, sizeof(rdpsndWinmmPlugin));
|
||||
|
||||
if (!winmm)
|
||||
return -1;
|
||||
|
||||
winmm->device.DisableConfirmThread = TRUE;
|
||||
|
||||
|
@ -36,6 +36,7 @@ static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
|
||||
int pos;
|
||||
UINT16 i;
|
||||
BOOL status;
|
||||
ULONG written;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_FORMATS);
|
||||
Stream_Write_UINT8(s, 0);
|
||||
@ -74,7 +75,7 @@ static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
|
||||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
@ -82,8 +83,8 @@ static BOOL rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s)
|
||||
|
||||
static BOOL rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream* s)
|
||||
{
|
||||
UINT16 timestamp = 0;
|
||||
BYTE confirmBlockNum = 0;
|
||||
UINT16 timestamp;
|
||||
BYTE confirmBlockNum;
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
return FALSE;
|
||||
@ -91,6 +92,9 @@ static BOOL rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream
|
||||
Stream_Read_UINT16(s, timestamp);
|
||||
Stream_Read_UINT8(s, confirmBlockNum);
|
||||
Stream_Seek_UINT8(s);
|
||||
|
||||
IFCALL(context->ConfirmBlock, context, confirmBlockNum, timestamp);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -191,37 +195,41 @@ static void* rdpsnd_server_thread(void* arg)
|
||||
UINT16 BodySize;
|
||||
HANDLE events[8];
|
||||
HANDLE ChannelEvent;
|
||||
DWORD BytesReturned;
|
||||
DWORD bytesReturned;
|
||||
RdpsndServerContext* context;
|
||||
BOOL doRun;
|
||||
BOOL waitingHeader;
|
||||
DWORD expectedBytes;
|
||||
|
||||
context = (RdpsndServerContext *)arg;
|
||||
|
||||
buffer = NULL;
|
||||
BytesReturned = 0;
|
||||
ChannelEvent = NULL;
|
||||
bytesReturned = 0;
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &BytesReturned))
|
||||
if (!WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE)))
|
||||
{
|
||||
if (BytesReturned == sizeof(HANDLE))
|
||||
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
|
||||
|
||||
WTSFreeMemory(buffer);
|
||||
fprintf(stderr, "%s: error during WTSVirtualChannelQuery(WTSVirtualEventHandle) or invalid returned size(%d)\n",
|
||||
__FUNCTION__, bytesReturned);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
|
||||
WTSFreeMemory(buffer);
|
||||
|
||||
nCount = 0;
|
||||
if (ChannelEvent)
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = context->priv->StopEvent;
|
||||
|
||||
if (!rdpsnd_server_send_formats(context, s))
|
||||
goto out;
|
||||
|
||||
doRun = TRUE;
|
||||
waitingHeader = TRUE;
|
||||
expectedBytes = 4;
|
||||
while (doRun)
|
||||
{
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
@ -229,31 +237,34 @@ static void* rdpsnd_server_thread(void* arg)
|
||||
if (WaitForSingleObject(context->priv->StopEvent, 0) == WAIT_OBJECT_0)
|
||||
break;
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s),
|
||||
Stream_Capacity(s), &BytesReturned))
|
||||
if (!WTSVirtualChannelRead(ChannelEvent, 0, (PCHAR)Stream_Pointer(s), expectedBytes, &bytesReturned))
|
||||
{
|
||||
if (!BytesReturned)
|
||||
break;
|
||||
fprintf(stderr, "%s: channel connection closed\n", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
expectedBytes -= bytesReturned;
|
||||
Stream_Seek(s, bytesReturned);
|
||||
|
||||
Stream_EnsureRemainingCapacity(s, BytesReturned);
|
||||
if (expectedBytes)
|
||||
continue;
|
||||
|
||||
if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, (PCHAR)Stream_Buffer(s),
|
||||
Stream_Capacity(s), &BytesReturned))
|
||||
break;
|
||||
Stream_SetPosition(s, 0);
|
||||
if (waitingHeader)
|
||||
{
|
||||
/* header case */
|
||||
Stream_Read_UINT8(s, msgType);
|
||||
Stream_Seek_UINT8(s); /* bPad */
|
||||
Stream_Read_UINT16(s, BodySize);
|
||||
|
||||
expectedBytes = BodySize;
|
||||
waitingHeader = FALSE;
|
||||
Stream_SetPosition(s, 0);
|
||||
Stream_EnsureCapacity(s, BodySize);
|
||||
if (expectedBytes)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 4)
|
||||
break;
|
||||
|
||||
Stream_Read_UINT8(s, msgType);
|
||||
Stream_Seek_UINT8(s); /* bPad */
|
||||
Stream_Read_UINT16(s, BodySize);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < BodySize)
|
||||
break;
|
||||
|
||||
/* when here we have the header + the body */
|
||||
switch (msgType)
|
||||
{
|
||||
case SNDC_WAVECONFIRM:
|
||||
@ -276,6 +287,10 @@ static void* rdpsnd_server_thread(void* arg)
|
||||
fprintf(stderr, "%s: UNKOWN MESSAGE TYPE!! (%#0X)\n\n", __FUNCTION__, msgType);
|
||||
break;
|
||||
}
|
||||
|
||||
expectedBytes = 4;
|
||||
waitingHeader = TRUE;
|
||||
Stream_SetPosition(s, 0);
|
||||
}
|
||||
|
||||
out:
|
||||
@ -352,7 +367,7 @@ static BOOL rdpsnd_server_select_format(RdpsndServerContext* context, int client
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context)
|
||||
static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp)
|
||||
{
|
||||
int size;
|
||||
BYTE* src;
|
||||
@ -361,6 +376,7 @@ static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context)
|
||||
BOOL status;
|
||||
AUDIO_FORMAT* format;
|
||||
int tbytes_per_frame;
|
||||
ULONG written;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
format = &context->client_formats[context->selected_client_format];
|
||||
@ -416,13 +432,13 @@ static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context)
|
||||
Stream_Write_UINT8(s, 0); /* bPad */
|
||||
Stream_Write_UINT16(s, size + fill_size + 8); /* BodySize */
|
||||
|
||||
Stream_Write_UINT16(s, 0); /* wTimeStamp */
|
||||
Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */
|
||||
Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */
|
||||
Stream_Write_UINT8(s, context->block_no); /* cBlockNo */
|
||||
Stream_Seek(s, 3); /* bPad */
|
||||
Stream_Write(s, src, 4);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
if (!status)
|
||||
goto out;
|
||||
Stream_SetPosition(s, 0);
|
||||
@ -435,7 +451,7 @@ static BOOL rdpsnd_server_send_audio_pdu(RdpsndServerContext* context)
|
||||
if (fill_size > 0)
|
||||
Stream_Zero(s, fill_size);
|
||||
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
|
||||
out:
|
||||
Stream_SetPosition(s, 0);
|
||||
@ -443,7 +459,7 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static BOOL rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf, int nframes)
|
||||
static BOOL rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf, int nframes, UINT16 wTimestamp)
|
||||
{
|
||||
int cframes;
|
||||
int cframesize;
|
||||
@ -464,7 +480,7 @@ static BOOL rdpsnd_server_send_samples(RdpsndServerContext* context, const void*
|
||||
|
||||
if (context->priv->out_pending_frames >= context->priv->out_frames)
|
||||
{
|
||||
if (!rdpsnd_server_send_audio_pdu(context))
|
||||
if (!rdpsnd_server_send_audio_pdu(context, wTimestamp))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@ -476,6 +492,7 @@ static BOOL rdpsnd_server_set_volume(RdpsndServerContext* context, int left, int
|
||||
{
|
||||
int pos;
|
||||
BOOL status;
|
||||
ULONG written;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
Stream_Write_UINT8(s, SNDC_SETVOLUME);
|
||||
@ -489,7 +506,7 @@ static BOOL rdpsnd_server_set_volume(RdpsndServerContext* context, int left, int
|
||||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
@ -499,6 +516,7 @@ static BOOL rdpsnd_server_close(RdpsndServerContext* context)
|
||||
{
|
||||
int pos;
|
||||
BOOL status;
|
||||
ULONG written;
|
||||
wStream* s = context->priv->rdpsnd_pdu;
|
||||
|
||||
if (context->selected_client_format < 0)
|
||||
@ -506,7 +524,7 @@ static BOOL rdpsnd_server_close(RdpsndServerContext* context)
|
||||
|
||||
if (context->priv->out_pending_frames > 0)
|
||||
{
|
||||
if (!rdpsnd_server_send_audio_pdu(context))
|
||||
if (!rdpsnd_server_send_audio_pdu(context, 0))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -520,7 +538,7 @@ static BOOL rdpsnd_server_close(RdpsndServerContext* context)
|
||||
Stream_SetPosition(s, 2);
|
||||
Stream_Write_UINT16(s, pos - 4);
|
||||
Stream_SetPosition(s, pos);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), NULL);
|
||||
status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
return status;
|
||||
|
@ -1,23 +0,0 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
define_channel("sample")
|
||||
|
||||
if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
@ -1,16 +0,0 @@
|
||||
set(OPTION_DEFAULT OFF)
|
||||
|
||||
if(WITH_SAMPLE)
|
||||
set(OPTION_CLIENT_DEFAULT ON)
|
||||
else()
|
||||
set(OPTION_CLIENT_DEFAULT OFF)
|
||||
endif()
|
||||
set(OPTION_SERVER_DEFAULT OFF)
|
||||
|
||||
define_channel_options(NAME "sample" TYPE "static"
|
||||
DESCRIPTION "Sample Virtual Channel Extension"
|
||||
SPECIFICATIONS ""
|
||||
DEFAULT ${OPTION_DEFAULT})
|
||||
|
||||
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
|
||||
define_channel_server_options(${OPTION_SERVER_DEFAULT})
|
@ -1,35 +0,0 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
define_channel_client("sample")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
sample_main.c
|
||||
sample_main.h)
|
||||
|
||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry")
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE freerdp
|
||||
MODULES freerdp-utils)
|
||||
|
||||
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets)
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
@ -1,11 +0,0 @@
|
||||
|
||||
This is a skeleton virtual channel plugin for freerdp
|
||||
To create your own virtual channel plugin, copy this directory
|
||||
then change all references of "skel" to your plugin name
|
||||
remember, plugin name are 7 chars or less, no spaces or funny chars
|
||||
|
||||
server_chan_test.cpp is an example of how to open a channel to the client
|
||||
this code needs to be compiled and run on the server in an rdp session
|
||||
when connect with a client that has the "skel" plugin loaded
|
||||
|
||||
Jay
|
@ -1,143 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Sample Virtual Channel
|
||||
*
|
||||
* Copyright 2009-2012 Jay Sorg
|
||||
* Copyright 2010-2012 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
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#include "sample_main.h"
|
||||
|
||||
struct sample_plugin
|
||||
{
|
||||
rdpSvcPlugin plugin;
|
||||
|
||||
/* put your private data here */
|
||||
};
|
||||
|
||||
static void sample_process_receive(rdpSvcPlugin* plugin, wStream* data_in)
|
||||
{
|
||||
int bytes;
|
||||
wStream* data_out;
|
||||
samplePlugin* sample = (samplePlugin*) plugin;
|
||||
|
||||
fprintf(stderr, "sample_process_receive:\n");
|
||||
|
||||
if (!sample)
|
||||
{
|
||||
fprintf(stderr, "sample_process_receive: sample is nil\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* process data in (from server) here */
|
||||
/* here we just send the same data back */
|
||||
|
||||
bytes = Stream_Capacity(data_in);
|
||||
fprintf(stderr, "sample_process_receive: got bytes %d\n", bytes);
|
||||
|
||||
if (bytes > 0)
|
||||
{
|
||||
data_out = Stream_New(NULL, bytes);
|
||||
Stream_Copy(data_out, data_in, bytes);
|
||||
/* svc_plugin_send takes ownership of data_out, that is why
|
||||
we do not free it */
|
||||
|
||||
bytes = Stream_GetPosition(data_in);
|
||||
fprintf(stderr, "sample_process_receive: sending bytes %d\n", bytes);
|
||||
|
||||
svc_plugin_send(plugin, data_out);
|
||||
}
|
||||
|
||||
Stream_Free(data_in, TRUE);
|
||||
}
|
||||
|
||||
static void sample_process_connect(rdpSvcPlugin* plugin)
|
||||
{
|
||||
samplePlugin* sample = (samplePlugin*) plugin;
|
||||
DEBUG_SVC("connecting");
|
||||
|
||||
fprintf(stderr, "sample_process_connect:\n");
|
||||
|
||||
if (!sample)
|
||||
return;
|
||||
}
|
||||
|
||||
static void sample_process_event(rdpSvcPlugin* plugin, wMessage* event)
|
||||
{
|
||||
fprintf(stderr, "sample_process_event:\n");
|
||||
|
||||
/* events coming from main freerdp window to plugin */
|
||||
/* send them back with svc_plugin_send_event */
|
||||
|
||||
freerdp_event_free(event);
|
||||
}
|
||||
|
||||
static void sample_process_terminate(rdpSvcPlugin* plugin)
|
||||
{
|
||||
samplePlugin* sample = (samplePlugin*) plugin;
|
||||
|
||||
fprintf(stderr, "sample_process_terminate:\n");
|
||||
|
||||
if (!sample)
|
||||
return;
|
||||
|
||||
/* put your cleanup here */
|
||||
|
||||
free(plugin);
|
||||
}
|
||||
|
||||
#define VirtualChannelEntry sample_VirtualChannelEntry
|
||||
|
||||
int VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
samplePlugin* _p;
|
||||
|
||||
_p = (samplePlugin*) malloc(sizeof(samplePlugin));
|
||||
ZeroMemory(_p, sizeof(samplePlugin));
|
||||
|
||||
_p->plugin.channel_def.options =
|
||||
CHANNEL_OPTION_INITIALIZED |
|
||||
CHANNEL_OPTION_ENCRYPT_RDP;
|
||||
|
||||
strcpy(_p->plugin.channel_def.name, "sample");
|
||||
|
||||
_p->plugin.connect_callback = sample_process_connect;
|
||||
_p->plugin.receive_callback = sample_process_receive;
|
||||
_p->plugin.event_callback = sample_process_event;
|
||||
_p->plugin.terminate_callback = sample_process_terminate;
|
||||
|
||||
svc_plugin_init((rdpSvcPlugin*) _p, pEntryPoints);
|
||||
|
||||
return 1;
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
// xrdp_chan_test.cpp : Basic test for virtual channel use.
|
||||
|
||||
// These headers are required for the windows terminal service calls.
|
||||
#include "windows.h"
|
||||
#include "wtsapi32.h"
|
||||
#include <string>
|
||||
|
||||
#define DSIZE 1024
|
||||
|
||||
int main()
|
||||
{
|
||||
// Initialize the data for send/receive
|
||||
char* data;
|
||||
char* data1;
|
||||
data = (char*)malloc(DSIZE);
|
||||
data1 = (char*)malloc(DSIZE);
|
||||
memset(data, 0xca, DSIZE);
|
||||
memset(data1, 0, DSIZE);
|
||||
|
||||
// Open the skel channel in current session
|
||||
void* channel = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "skel", 0);
|
||||
|
||||
unsigned long written = 0;
|
||||
// Write the data to the channel
|
||||
bool ret = WTSVirtualChannelWrite(channel, data, DSIZE, &written);
|
||||
if (!ret)
|
||||
{
|
||||
long err = GetLastError();
|
||||
fprintf(stderr, "error 0x%8.8x\n", err);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = WTSVirtualChannelRead(channel, 100, data1, DSIZE, &written);
|
||||
if (!ret)
|
||||
{
|
||||
long err = GetLastError();
|
||||
fprintf(stderr, "error 0x%8.8x\n", err);
|
||||
return 1;
|
||||
}
|
||||
if (written != DSIZE)
|
||||
{
|
||||
fprintf(stderr, "error read %d\n", written);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = WTSVirtualChannelClose(channel);
|
||||
if (memcmp(data, data1, DSIZE) == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "error data no match\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Success!\n");
|
||||
|
||||
Sleep(2000);
|
||||
return 0;
|
||||
}
|
@ -53,7 +53,6 @@
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
typedef struct _SERIAL_DEVICE SERIAL_DEVICE;
|
||||
|
||||
@ -100,13 +99,10 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
FileId = 0;
|
||||
|
||||
DEBUG_WARN("failed to create %s", path);
|
||||
}
|
||||
else
|
||||
{
|
||||
serial->tty = tty;
|
||||
DEBUG_SVC("%s(%d) created.", serial->path, FileId);
|
||||
}
|
||||
|
||||
Stream_Write_UINT32(irp->output, FileId); /* FileId (4 bytes) */
|
||||
@ -126,12 +122,9 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
|
||||
if (!tty)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
DEBUG_WARN("tty not valid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("%s(%d) closed.", serial->path, tty->id);
|
||||
|
||||
serial_tty_free(tty);
|
||||
serial->tty = NULL;
|
||||
}
|
||||
@ -156,8 +149,6 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("tty not valid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -169,12 +160,10 @@ static void serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("read %s(%d) failed.", serial->path, tty->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("read %llu-%llu from %d", Offset, Offset + Length, tty->id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -207,8 +196,6 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
Length = 0;
|
||||
|
||||
DEBUG_WARN("tty not valid.");
|
||||
|
||||
Stream_Write_UINT32(irp->output, Length); /* Length (4 bytes) */
|
||||
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
|
||||
irp->Complete(irp);
|
||||
@ -252,8 +239,6 @@ static void serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
|
||||
{
|
||||
irp->IoStatus = STATUS_UNSUCCESSFUL;
|
||||
OutputBufferLength = 0;
|
||||
|
||||
DEBUG_WARN("tty not valid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -291,7 +276,6 @@ static void serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_WARN("MajorFunction 0x%X not supported", irp->MajorFunction);
|
||||
irp->IoStatus = STATUS_NOT_SUPPORTED;
|
||||
irp->Complete(irp);
|
||||
break;
|
||||
|
@ -30,7 +30,6 @@
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -119,19 +118,16 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
case IOCTL_SERIAL_SET_BAUD_RATE:
|
||||
Stream_Read_UINT32(input, tty->baud_rate);
|
||||
tty_set_termios(tty);
|
||||
DEBUG_SVC("SERIAL_SET_BAUD_RATE %d", tty->baud_rate);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_GET_BAUD_RATE:
|
||||
OutputBufferLength = 4;
|
||||
Stream_Write_UINT32(output, tty->baud_rate);
|
||||
DEBUG_SVC("SERIAL_GET_BAUD_RATE %d", tty->baud_rate);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_QUEUE_SIZE:
|
||||
Stream_Read_UINT32(input, tty->queue_in_size);
|
||||
Stream_Read_UINT32(input, tty->queue_out_size);
|
||||
DEBUG_SVC("SERIAL_SET_QUEUE_SIZE in %d out %d", tty->queue_in_size, tty->queue_out_size);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_LINE_CONTROL:
|
||||
@ -139,12 +135,9 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
Stream_Read_UINT8(input, tty->parity);
|
||||
Stream_Read_UINT8(input, tty->word_length);
|
||||
tty_set_termios(tty);
|
||||
DEBUG_SVC("SERIAL_SET_LINE_CONTROL stop %d parity %d word %d",
|
||||
tty->stop_bits, tty->parity, tty->word_length);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_GET_LINE_CONTROL:
|
||||
DEBUG_SVC("SERIAL_GET_LINE_CONTROL");
|
||||
OutputBufferLength = 3;
|
||||
Stream_Write_UINT8(output, tty->stop_bits);
|
||||
Stream_Write_UINT8(output, tty->parity);
|
||||
@ -152,25 +145,21 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_IMMEDIATE_CHAR:
|
||||
DEBUG_SVC("SERIAL_IMMEDIATE_CHAR");
|
||||
Stream_Read_UINT8(input, immediate);
|
||||
tty_write_data(tty, &immediate, 1);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_CONFIG_SIZE:
|
||||
DEBUG_SVC("SERIAL_CONFIG_SIZE");
|
||||
OutputBufferLength = 4;
|
||||
Stream_Write_UINT32(output, 0);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_GET_CHARS:
|
||||
DEBUG_SVC("SERIAL_GET_CHARS");
|
||||
OutputBufferLength = 6;
|
||||
Stream_Write(output, tty->chars, 6);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_CHARS:
|
||||
DEBUG_SVC("SERIAL_SET_CHARS");
|
||||
Stream_Read(input, tty->chars, 6);
|
||||
tty_set_termios(tty);
|
||||
break;
|
||||
@ -182,8 +171,6 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
Stream_Write_UINT32(output, tty->xonoff);
|
||||
Stream_Write_UINT32(output, tty->onlimit);
|
||||
Stream_Write_UINT32(output, tty->offlimit);
|
||||
DEBUG_SVC("IOCTL_SERIAL_GET_HANDFLOW %X %X %X %X",
|
||||
tty->control, tty->xonoff, tty->onlimit, tty->offlimit);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_HANDFLOW:
|
||||
@ -191,8 +178,6 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
Stream_Read_UINT32(input, tty->xonoff);
|
||||
Stream_Read_UINT32(input, tty->onlimit);
|
||||
Stream_Read_UINT32(input, tty->offlimit);
|
||||
DEBUG_SVC("IOCTL_SERIAL_SET_HANDFLOW %X %X %X %X",
|
||||
tty->control, tty->xonoff, tty->onlimit, tty->offlimit);
|
||||
tty_set_termios(tty);
|
||||
break;
|
||||
|
||||
@ -211,17 +196,9 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
tty->read_total_timeout_multiplier = 0;
|
||||
}
|
||||
|
||||
DEBUG_SVC("SERIAL_SET_TIMEOUTS read timeout %d %d %d",
|
||||
tty->read_interval_timeout,
|
||||
tty->read_total_timeout_multiplier,
|
||||
tty->read_total_timeout_constant);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_GET_TIMEOUTS:
|
||||
DEBUG_SVC("SERIAL_GET_TIMEOUTS read timeout %d %d %d",
|
||||
tty->read_interval_timeout,
|
||||
tty->read_total_timeout_multiplier,
|
||||
tty->read_total_timeout_constant);
|
||||
OutputBufferLength = 20;
|
||||
Stream_Write_UINT32(output, tty->read_interval_timeout);
|
||||
Stream_Write_UINT32(output, tty->read_total_timeout_multiplier);
|
||||
@ -231,18 +208,15 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_GET_WAIT_MASK:
|
||||
DEBUG_SVC("SERIAL_GET_WAIT_MASK %X", tty->wait_mask);
|
||||
OutputBufferLength = 4;
|
||||
Stream_Write_UINT32(output, tty->wait_mask);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_WAIT_MASK:
|
||||
Stream_Read_UINT32(input, tty->wait_mask);
|
||||
DEBUG_SVC("SERIAL_SET_WAIT_MASK %X", tty->wait_mask);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_DTR:
|
||||
DEBUG_SVC("SERIAL_SET_DTR");
|
||||
ioctl(tty->fd, TIOCMGET, &result);
|
||||
result |= TIOCM_DTR;
|
||||
ioctl(tty->fd, TIOCMSET, &result);
|
||||
@ -250,7 +224,6 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_CLR_DTR:
|
||||
DEBUG_SVC("SERIAL_CLR_DTR");
|
||||
ioctl(tty->fd, TIOCMGET, &result);
|
||||
result &= ~TIOCM_DTR;
|
||||
ioctl(tty->fd, TIOCMSET, &result);
|
||||
@ -258,7 +231,6 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_RTS:
|
||||
DEBUG_SVC("SERIAL_SET_RTS");
|
||||
ioctl(tty->fd, TIOCMGET, &result);
|
||||
result |= TIOCM_RTS;
|
||||
ioctl(tty->fd, TIOCMSET, &result);
|
||||
@ -266,7 +238,6 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_CLR_RTS:
|
||||
DEBUG_SVC("SERIAL_CLR_RTS");
|
||||
ioctl(tty->fd, TIOCMGET, &result);
|
||||
result &= ~TIOCM_RTS;
|
||||
ioctl(tty->fd, TIOCMSET, &result);
|
||||
@ -290,7 +261,6 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
if (result & TIOCM_RTS)
|
||||
modemstate |= SERIAL_MS_RTS;
|
||||
#endif
|
||||
DEBUG_SVC("SERIAL_GET_MODEMSTATUS %X", modemstate);
|
||||
OutputBufferLength = 4;
|
||||
Stream_Write_UINT32(output, modemstate);
|
||||
break;
|
||||
@ -305,23 +275,18 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
ioctl(tty->fd, TIOCINQ, &result);
|
||||
#endif
|
||||
Stream_Write_UINT32(output, result); /* Amount in in queue */
|
||||
if (result)
|
||||
DEBUG_SVC("SERIAL_GET_COMMSTATUS in queue %d", result);
|
||||
|
||||
result = 0;
|
||||
#ifdef TIOCOUTQ
|
||||
ioctl(tty->fd, TIOCOUTQ, &result);
|
||||
#endif
|
||||
Stream_Write_UINT32(output, result); /* Amount in out queue */
|
||||
DEBUG_SVC("SERIAL_GET_COMMSTATUS out queue %d", result);
|
||||
|
||||
Stream_Write_UINT8(output, 0); /* EofReceived */
|
||||
Stream_Write_UINT8(output, 0); /* WaitForImmediate */
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_PURGE:
|
||||
Stream_Read_UINT32(input, purge_mask);
|
||||
DEBUG_SVC("SERIAL_PURGE purge_mask %X", purge_mask);
|
||||
|
||||
/* See http://msdn.microsoft.com/en-us/library/ms901431.aspx
|
||||
PURGE_TXCLEAR Clears the output buffer, if the driver has one.
|
||||
@ -330,25 +295,16 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
It clearly states to clear the *driver* buffer, not the port buffer
|
||||
*/
|
||||
|
||||
#ifdef DEBUG_SVC
|
||||
if (purge_mask & SERIAL_PURGE_TXCLEAR)
|
||||
DEBUG_SVC("Ignoring SERIAL_PURGE_TXCLEAR");
|
||||
if (purge_mask & SERIAL_PURGE_RXCLEAR)
|
||||
DEBUG_SVC("Ignoring SERIAL_PURGE_RXCLEAR");
|
||||
#endif
|
||||
|
||||
if (purge_mask & SERIAL_PURGE_TXABORT)
|
||||
*abortIo |= SERIAL_ABORT_IO_WRITE;
|
||||
if (purge_mask & SERIAL_PURGE_RXABORT)
|
||||
*abortIo |= SERIAL_ABORT_IO_READ;
|
||||
break;
|
||||
case IOCTL_SERIAL_WAIT_ON_MASK:
|
||||
DEBUG_SVC("SERIAL_WAIT_ON_MASK %X", tty->wait_mask);
|
||||
tty->event_pending = 1;
|
||||
OutputBufferLength = 4;
|
||||
if (serial_tty_get_event(tty, &result))
|
||||
{
|
||||
DEBUG_SVC("WAIT end event = %X", result);
|
||||
Stream_Write_UINT32(output, result);
|
||||
break;
|
||||
}
|
||||
@ -356,29 +312,23 @@ UINT32 serial_tty_control(SERIAL_TTY* tty, UINT32 IoControlCode, wStream* input,
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_BREAK_ON:
|
||||
DEBUG_SVC("SERIAL_SET_BREAK_ON");
|
||||
tcsendbreak(tty->fd, 0);
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_RESET_DEVICE:
|
||||
DEBUG_SVC("SERIAL_RESET_DEVICE");
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_BREAK_OFF:
|
||||
DEBUG_SVC("SERIAL_SET_BREAK_OFF");
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_XOFF:
|
||||
DEBUG_SVC("SERIAL_SET_XOFF");
|
||||
break;
|
||||
|
||||
case IOCTL_SERIAL_SET_XON:
|
||||
DEBUG_SVC("SERIAL_SET_XON");
|
||||
tcflow(tty->fd, TCION);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_SVC("NOT FOUND IoControlCode SERIAL IOCTL 0x%08X", IoControlCode);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
@ -457,11 +407,7 @@ BOOL serial_tty_read(SERIAL_TTY* tty, BYTE* buffer, UINT32* Length)
|
||||
status = read(tty->fd, buffer, *Length);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
DEBUG_WARN("failed with %zd, errno=[%d] %s\n",
|
||||
status, errno, strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tty->event_txempty = status;
|
||||
*Length = status;
|
||||
@ -535,13 +481,12 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
|
||||
if (tty->fd < 0)
|
||||
{
|
||||
perror("open");
|
||||
DEBUG_WARN("failed to open device %s", path);
|
||||
serial_tty_free(tty);
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_SVC("tty fd %d successfully opened", tty->fd);
|
||||
|
||||
}
|
||||
|
||||
tty->ptermios = (struct termios*) calloc(1, sizeof(struct termios));
|
||||
@ -563,7 +508,6 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
|
||||
|
||||
if (!tty_get_termios(tty))
|
||||
{
|
||||
DEBUG_WARN("%s access denied", path);
|
||||
fflush(stdout);
|
||||
serial_tty_free(tty);
|
||||
return NULL;
|
||||
@ -589,7 +533,6 @@ SERIAL_TTY* serial_tty_new(const char* path, UINT32 id)
|
||||
/* all read and writes should be non-blocking */
|
||||
if (fcntl(tty->fd, F_SETFL, O_NONBLOCK) == -1)
|
||||
{
|
||||
DEBUG_WARN("%s fcntl", path);
|
||||
perror("fcntl");
|
||||
serial_tty_free(tty) ;
|
||||
return NULL;
|
||||
@ -620,15 +563,12 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
|
||||
|
||||
if (bytes > 0)
|
||||
{
|
||||
DEBUG_SVC("bytes %d", bytes);
|
||||
|
||||
if (bytes > tty->event_rlsd)
|
||||
{
|
||||
tty->event_rlsd = bytes;
|
||||
|
||||
if (tty->wait_mask & SERIAL_EV_RLSD)
|
||||
{
|
||||
DEBUG_SVC("SERIAL_EV_RLSD");
|
||||
*result |= SERIAL_EV_RLSD;
|
||||
status = TRUE;
|
||||
}
|
||||
@ -636,14 +576,12 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
|
||||
|
||||
if ((bytes > 1) && (tty->wait_mask & SERIAL_EV_RXFLAG))
|
||||
{
|
||||
DEBUG_SVC("SERIAL_EV_RXFLAG bytes %d", bytes);
|
||||
*result |= SERIAL_EV_RXFLAG;
|
||||
status = TRUE;
|
||||
}
|
||||
|
||||
if ((tty->wait_mask & SERIAL_EV_RXCHAR))
|
||||
{
|
||||
DEBUG_SVC("SERIAL_EV_RXCHAR bytes %d", bytes);
|
||||
*result |= SERIAL_EV_RXCHAR;
|
||||
status = TRUE;
|
||||
}
|
||||
@ -658,7 +596,6 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
|
||||
ioctl(tty->fd, TIOCOUTQ, &bytes);
|
||||
if ((bytes == 0) && (tty->event_txempty > 0) && (tty->wait_mask & SERIAL_EV_TXEMPTY))
|
||||
{
|
||||
DEBUG_SVC("SERIAL_EV_TXEMPTY");
|
||||
*result |= SERIAL_EV_TXEMPTY;
|
||||
status = TRUE;
|
||||
}
|
||||
@ -669,9 +606,9 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
|
||||
if ((bytes & TIOCM_DSR) != tty->event_dsr)
|
||||
{
|
||||
tty->event_dsr = bytes & TIOCM_DSR;
|
||||
|
||||
if (tty->wait_mask & SERIAL_EV_DSR)
|
||||
{
|
||||
DEBUG_SVC("SERIAL_EV_DSR %s", (bytes & TIOCM_DSR) ? "ON" : "OFF");
|
||||
*result |= SERIAL_EV_DSR;
|
||||
status = TRUE;
|
||||
}
|
||||
@ -680,9 +617,9 @@ BOOL serial_tty_get_event(SERIAL_TTY* tty, UINT32* result)
|
||||
if ((bytes & TIOCM_CTS) != tty->event_cts)
|
||||
{
|
||||
tty->event_cts = bytes & TIOCM_CTS;
|
||||
|
||||
if (tty->wait_mask & SERIAL_EV_CTS)
|
||||
{
|
||||
DEBUG_SVC("SERIAL_EV_CTS %s", (bytes & TIOCM_CTS) ? "ON" : "OFF");
|
||||
*result |= SERIAL_EV_CTS;
|
||||
status = TRUE;
|
||||
}
|
||||
@ -700,8 +637,6 @@ static BOOL tty_get_termios(SERIAL_TTY* tty)
|
||||
struct termios* ptermios;
|
||||
ptermios = tty->ptermios;
|
||||
|
||||
DEBUG_SVC("tcgetattr? %d", tcgetattr(tty->fd, ptermios) >= 0);
|
||||
|
||||
if (tcgetattr(tty->fd, ptermios) < 0)
|
||||
return FALSE;
|
||||
|
||||
|
@ -55,7 +55,7 @@ if(WITH_FFMPEG)
|
||||
add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "ffmpeg" "decoder")
|
||||
endif()
|
||||
|
||||
if(WITH_GSTREAMER)
|
||||
if(WITH_GSTREAMER_0_10 OR WITH_GSTREAMER_1_0)
|
||||
set(XRANDR_FEATURE_TYPE "REQUIRED")
|
||||
set(XRANDR_FEATURE_PURPOSE "X11 randr")
|
||||
set(XRANDR_FEATURE_DESCRIPTION "X11 randr extension")
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
@ -41,225 +40,194 @@ typedef struct _TSMFALSAAudioDevice
|
||||
ITSMFAudioDevice iface;
|
||||
|
||||
char device[32];
|
||||
snd_pcm_t* out_handle;
|
||||
snd_pcm_t *out_handle;
|
||||
UINT32 source_rate;
|
||||
UINT32 actual_rate;
|
||||
UINT32 source_channels;
|
||||
UINT32 actual_channels;
|
||||
UINT32 bytes_per_sample;
|
||||
|
||||
FREERDP_DSP_CONTEXT* dsp_context;
|
||||
FREERDP_DSP_CONTEXT *dsp_context;
|
||||
} TSMFAlsaAudioDevice;
|
||||
|
||||
static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice* alsa)
|
||||
static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice *alsa)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = snd_pcm_open(&alsa->out_handle, alsa->device, SND_PCM_STREAM_PLAYBACK, 0);
|
||||
|
||||
if (error < 0)
|
||||
if(error < 0)
|
||||
{
|
||||
DEBUG_WARN("failed to open device %s", alsa->device);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DEBUG_DVC("open device %s", alsa->device);
|
||||
DEBUG_TSMF("open device %s", alsa->device);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_alsa_open(ITSMFAudioDevice* audio, const char* device)
|
||||
static BOOL tsmf_alsa_open(ITSMFAudioDevice *audio, const char *device)
|
||||
{
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
if (!device)
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
if(!device)
|
||||
{
|
||||
if (!alsa->device[0])
|
||||
if(!alsa->device[0])
|
||||
strncpy(alsa->device, "default", sizeof(alsa->device));
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(alsa->device, device, sizeof(alsa->device));
|
||||
}
|
||||
|
||||
return tsmf_alsa_open_device(alsa);
|
||||
}
|
||||
|
||||
static BOOL tsmf_alsa_set_format(ITSMFAudioDevice* audio,
|
||||
UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample)
|
||||
static BOOL tsmf_alsa_set_format(ITSMFAudioDevice *audio,
|
||||
UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample)
|
||||
{
|
||||
int error;
|
||||
snd_pcm_uframes_t frames;
|
||||
snd_pcm_hw_params_t* hw_params;
|
||||
snd_pcm_sw_params_t* sw_params;
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
if (!alsa->out_handle)
|
||||
snd_pcm_hw_params_t *hw_params;
|
||||
snd_pcm_sw_params_t *sw_params;
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
if(!alsa->out_handle)
|
||||
return FALSE;
|
||||
|
||||
snd_pcm_drop(alsa->out_handle);
|
||||
|
||||
alsa->actual_rate = alsa->source_rate = sample_rate;
|
||||
alsa->actual_channels = alsa->source_channels = channels;
|
||||
alsa->bytes_per_sample = bits_per_sample / 8;
|
||||
|
||||
error = snd_pcm_hw_params_malloc(&hw_params);
|
||||
|
||||
if (error < 0)
|
||||
if(error < 0)
|
||||
{
|
||||
DEBUG_WARN("snd_pcm_hw_params_malloc failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
snd_pcm_hw_params_any(alsa->out_handle, hw_params);
|
||||
snd_pcm_hw_params_set_access(alsa->out_handle, hw_params,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
snd_pcm_hw_params_set_format(alsa->out_handle, hw_params,
|
||||
SND_PCM_FORMAT_S16_LE);
|
||||
SND_PCM_FORMAT_S16_LE);
|
||||
snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params,
|
||||
&alsa->actual_rate, NULL);
|
||||
&alsa->actual_rate, NULL);
|
||||
snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params,
|
||||
&alsa->actual_channels);
|
||||
&alsa->actual_channels);
|
||||
frames = sample_rate;
|
||||
snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params,
|
||||
&frames);
|
||||
&frames);
|
||||
snd_pcm_hw_params(alsa->out_handle, hw_params);
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
|
||||
error = snd_pcm_sw_params_malloc(&sw_params);
|
||||
|
||||
if (error < 0)
|
||||
if(error < 0)
|
||||
{
|
||||
DEBUG_WARN("snd_pcm_sw_params_malloc");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
snd_pcm_sw_params_current(alsa->out_handle, sw_params);
|
||||
snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params,
|
||||
frames / 2);
|
||||
frames / 2);
|
||||
snd_pcm_sw_params(alsa->out_handle, sw_params);
|
||||
snd_pcm_sw_params_free(sw_params);
|
||||
|
||||
snd_pcm_prepare(alsa->out_handle);
|
||||
|
||||
DEBUG_DVC("sample_rate %d channels %d bits_per_sample %d",
|
||||
sample_rate, channels, bits_per_sample);
|
||||
DEBUG_DVC("hardware buffer %d frames", (int)frames);
|
||||
|
||||
if ((alsa->actual_rate != alsa->source_rate) ||
|
||||
(alsa->actual_channels != alsa->source_channels))
|
||||
DEBUG_TSMF("sample_rate %d channels %d bits_per_sample %d",
|
||||
sample_rate, channels, bits_per_sample);
|
||||
DEBUG_TSMF("hardware buffer %d frames", (int)frames);
|
||||
if((alsa->actual_rate != alsa->source_rate) ||
|
||||
(alsa->actual_channels != alsa->source_channels))
|
||||
{
|
||||
DEBUG_DVC("actual rate %d / channel %d is different "
|
||||
"from source rate %d / channel %d, resampling required.",
|
||||
alsa->actual_rate, alsa->actual_channels,
|
||||
alsa->source_rate, alsa->source_channels);
|
||||
DEBUG_TSMF("actual rate %d / channel %d is different "
|
||||
"from source rate %d / channel %d, resampling required.",
|
||||
alsa->actual_rate, alsa->actual_channels,
|
||||
alsa->source_rate, alsa->source_channels);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_alsa_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size)
|
||||
static BOOL tsmf_alsa_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size)
|
||||
{
|
||||
int len;
|
||||
int error;
|
||||
int frames;
|
||||
BYTE* end;
|
||||
BYTE* src;
|
||||
BYTE* pindex;
|
||||
BYTE *end;
|
||||
BYTE *src;
|
||||
BYTE *pindex;
|
||||
int rbytes_per_frame;
|
||||
int sbytes_per_frame;
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
DEBUG_DVC("data_size %d", data_size);
|
||||
|
||||
if (alsa->out_handle)
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
DEBUG_TSMF("data_size %d", data_size);
|
||||
if(alsa->out_handle)
|
||||
{
|
||||
sbytes_per_frame = alsa->source_channels * alsa->bytes_per_sample;
|
||||
rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_sample;
|
||||
|
||||
if ((alsa->source_rate == alsa->actual_rate) &&
|
||||
(alsa->source_channels == alsa->actual_channels))
|
||||
if((alsa->source_rate == alsa->actual_rate) &&
|
||||
(alsa->source_channels == alsa->actual_channels))
|
||||
{
|
||||
src = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
alsa->dsp_context->resample(alsa->dsp_context, data, alsa->bytes_per_sample,
|
||||
alsa->source_channels, alsa->source_rate, data_size / sbytes_per_frame,
|
||||
alsa->actual_channels, alsa->actual_rate);
|
||||
alsa->source_channels, alsa->source_rate, data_size / sbytes_per_frame,
|
||||
alsa->actual_channels, alsa->actual_rate);
|
||||
frames = alsa->dsp_context->resampled_frames;
|
||||
DEBUG_DVC("resampled %d frames at %d to %d frames at %d",
|
||||
data_size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate);
|
||||
DEBUG_TSMF("resampled %d frames at %d to %d frames at %d",
|
||||
data_size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate);
|
||||
data_size = frames * rbytes_per_frame;
|
||||
src = alsa->dsp_context->resampled_buffer;
|
||||
}
|
||||
|
||||
pindex = src;
|
||||
end = pindex + data_size;
|
||||
while (pindex < end)
|
||||
while(pindex < end)
|
||||
{
|
||||
len = end - pindex;
|
||||
frames = len / rbytes_per_frame;
|
||||
error = snd_pcm_writei(alsa->out_handle, pindex, frames);
|
||||
|
||||
if (error == -EPIPE)
|
||||
if(error == -EPIPE)
|
||||
{
|
||||
snd_pcm_recover(alsa->out_handle, error, 0);
|
||||
error = 0;
|
||||
}
|
||||
else if (error < 0)
|
||||
{
|
||||
DEBUG_DVC("error len %d", error);
|
||||
snd_pcm_close(alsa->out_handle);
|
||||
alsa->out_handle = 0;
|
||||
tsmf_alsa_open_device(alsa);
|
||||
else
|
||||
if(error < 0)
|
||||
{
|
||||
DEBUG_TSMF("error len %d", error);
|
||||
snd_pcm_close(alsa->out_handle);
|
||||
alsa->out_handle = 0;
|
||||
tsmf_alsa_open_device(alsa);
|
||||
break;
|
||||
}
|
||||
DEBUG_TSMF("%d frames played.", error);
|
||||
if(error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_DVC("%d frames played.", error);
|
||||
|
||||
if (error == 0)
|
||||
break;
|
||||
|
||||
pindex += error * rbytes_per_frame;
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice* audio)
|
||||
static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice *audio)
|
||||
{
|
||||
UINT64 latency = 0;
|
||||
snd_pcm_sframes_t frames = 0;
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
if (alsa->out_handle && alsa->actual_rate > 0 &&
|
||||
snd_pcm_delay(alsa->out_handle, &frames) == 0 &&
|
||||
frames > 0)
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
if(alsa->out_handle && alsa->actual_rate > 0 &&
|
||||
snd_pcm_delay(alsa->out_handle, &frames) == 0 &&
|
||||
frames > 0)
|
||||
{
|
||||
latency = ((UINT64)frames) * 10000000LL / (UINT64) alsa->actual_rate;
|
||||
}
|
||||
|
||||
return latency;
|
||||
}
|
||||
|
||||
static void tsmf_alsa_flush(ITSMFAudioDevice* audio)
|
||||
static void tsmf_alsa_flush(ITSMFAudioDevice *audio)
|
||||
{
|
||||
}
|
||||
|
||||
static void tsmf_alsa_free(ITSMFAudioDevice* audio)
|
||||
static void tsmf_alsa_free(ITSMFAudioDevice *audio)
|
||||
{
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
if (alsa->out_handle)
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
DEBUG_TSMF("");
|
||||
if(alsa->out_handle)
|
||||
{
|
||||
snd_pcm_drain(alsa->out_handle);
|
||||
snd_pcm_close(alsa->out_handle);
|
||||
}
|
||||
|
||||
freerdp_dsp_context_free(alsa->dsp_context);
|
||||
free(alsa);
|
||||
}
|
||||
@ -268,21 +236,17 @@ static void tsmf_alsa_free(ITSMFAudioDevice* audio)
|
||||
#define freerdp_tsmf_client_audio_subsystem_entry alsa_freerdp_tsmf_client_audio_subsystem_entry
|
||||
#endif
|
||||
|
||||
ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void)
|
||||
ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void)
|
||||
{
|
||||
TSMFAlsaAudioDevice* alsa;
|
||||
|
||||
alsa = (TSMFAlsaAudioDevice*) malloc(sizeof(TSMFAlsaAudioDevice));
|
||||
TSMFAlsaAudioDevice *alsa;
|
||||
alsa = (TSMFAlsaAudioDevice *) malloc(sizeof(TSMFAlsaAudioDevice));
|
||||
ZeroMemory(alsa, sizeof(TSMFAlsaAudioDevice));
|
||||
|
||||
alsa->iface.Open = tsmf_alsa_open;
|
||||
alsa->iface.SetFormat = tsmf_alsa_set_format;
|
||||
alsa->iface.Play = tsmf_alsa_play;
|
||||
alsa->iface.GetLatency = tsmf_alsa_get_latency;
|
||||
alsa->iface.Flush = tsmf_alsa_flush;
|
||||
alsa->iface.Free = tsmf_alsa_free;
|
||||
|
||||
alsa->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
return (ITSMFAudioDevice*) alsa;
|
||||
return (ITSMFAudioDevice *) alsa;
|
||||
}
|
||||
|
@ -32,8 +32,6 @@
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "tsmf_constants.h"
|
||||
#include "tsmf_decoder.h"
|
||||
|
||||
@ -59,55 +57,47 @@ typedef struct _TSMFFFmpegDecoder
|
||||
#else
|
||||
enum AVCodecID codec_id;
|
||||
#endif
|
||||
AVCodecContext* codec_context;
|
||||
AVCodec* codec;
|
||||
AVFrame* frame;
|
||||
AVCodecContext *codec_context;
|
||||
AVCodec *codec;
|
||||
AVFrame *frame;
|
||||
int prepared;
|
||||
|
||||
BYTE* decoded_data;
|
||||
BYTE *decoded_data;
|
||||
UINT32 decoded_size;
|
||||
UINT32 decoded_size_max;
|
||||
} TSMFFFmpegDecoder;
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder* decoder)
|
||||
static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder *decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
mdecoder->codec_context = avcodec_alloc_context3(NULL);
|
||||
|
||||
if (!mdecoder->codec_context)
|
||||
if(!mdecoder->codec_context)
|
||||
{
|
||||
DEBUG_WARN("avcodec_alloc_context failed.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
|
||||
static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
mdecoder->codec_context->width = media_type->Width;
|
||||
mdecoder->codec_context->height = media_type->Height;
|
||||
mdecoder->codec_context->bit_rate = media_type->BitRate;
|
||||
mdecoder->codec_context->time_base.den = media_type->SamplesPerSecond.Numerator;
|
||||
mdecoder->codec_context->time_base.num = media_type->SamplesPerSecond.Denominator;
|
||||
|
||||
mdecoder->frame = avcodec_alloc_frame();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
|
||||
static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
mdecoder->codec_context->sample_rate = media_type->SamplesPerSecond.Numerator;
|
||||
mdecoder->codec_context->bit_rate = media_type->BitRate;
|
||||
mdecoder->codec_context->channels = media_type->Channels;
|
||||
mdecoder->codec_context->block_align = media_type->BlockAlign;
|
||||
|
||||
#if LIBAVCODEC_VERSION_MAJOR < 55
|
||||
#ifdef AV_CPU_FLAG_SSE2
|
||||
mdecoder->codec_context->dsp_mask = AV_CPU_FLAG_SSE2 | AV_CPU_FLAG_MMX2;
|
||||
@ -125,43 +115,38 @@ static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MED
|
||||
av_set_cpu_flags_mask(FF_MM_SSE2 | FF_MM_MMX2);
|
||||
#endif
|
||||
#endif /* LIBAVCODEC_VERSION_MAJOR < 55 */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
|
||||
static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
BYTE* p;
|
||||
BYTE *p;
|
||||
UINT32 size;
|
||||
const BYTE* s;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
const BYTE *s;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id);
|
||||
|
||||
if (!mdecoder->codec)
|
||||
if(!mdecoder->codec)
|
||||
{
|
||||
DEBUG_WARN("avcodec_find_decoder failed.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mdecoder->codec_context->codec_id = mdecoder->codec_id;
|
||||
mdecoder->codec_context->codec_type = mdecoder->media_type;
|
||||
|
||||
if (mdecoder->media_type == AVMEDIA_TYPE_VIDEO)
|
||||
if(mdecoder->media_type == AVMEDIA_TYPE_VIDEO)
|
||||
{
|
||||
if (!tsmf_ffmpeg_init_video_stream(decoder, media_type))
|
||||
if(!tsmf_ffmpeg_init_video_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
}
|
||||
else if (mdecoder->media_type == AVMEDIA_TYPE_AUDIO)
|
||||
else
|
||||
if(mdecoder->media_type == AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
if(!tsmf_ffmpeg_init_audio_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
}
|
||||
if(media_type->ExtraData)
|
||||
{
|
||||
if (!tsmf_ffmpeg_init_audio_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (media_type->ExtraData)
|
||||
{
|
||||
if (media_type->SubType == TSMF_SUB_TYPE_AVC1 &&
|
||||
media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
|
||||
if(media_type->SubType == TSMF_SUB_TYPE_AVC1 &&
|
||||
media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
|
||||
{
|
||||
/* The extradata format that FFmpeg uses is following CodecPrivate in Matroska.
|
||||
See http://haali.su/mkv/codecs.pdf */
|
||||
@ -194,33 +179,27 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP
|
||||
memset(mdecoder->codec_context->extradata + media_type->ExtraDataSize, 0, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED)
|
||||
if(mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED)
|
||||
mdecoder->codec_context->flags |= CODEC_FLAG_TRUNCATED;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder* decoder)
|
||||
static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder *decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0)
|
||||
{
|
||||
DEBUG_WARN("avcodec_open2 failed.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mdecoder->prepared = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type)
|
||||
static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
switch (media_type->MajorType)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
switch(media_type->MajorType)
|
||||
{
|
||||
case TSMF_MAJOR_TYPE_VIDEO:
|
||||
mdecoder->media_type = AVMEDIA_TYPE_VIDEO;
|
||||
@ -231,7 +210,7 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
switch (media_type->SubType)
|
||||
switch(media_type->SubType)
|
||||
{
|
||||
case TSMF_SUB_TYPE_WVC1:
|
||||
mdecoder->codec_id = CODEC_ID_VC1;
|
||||
@ -259,7 +238,7 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi
|
||||
/* For AAC the pFormat is a HEAACWAVEINFO struct, and the codec data
|
||||
is at the end of it. See
|
||||
http://msdn.microsoft.com/en-us/library/dd757806.aspx */
|
||||
if (media_type->ExtraData)
|
||||
if(media_type->ExtraData)
|
||||
{
|
||||
media_type->ExtraData += 12;
|
||||
media_type->ExtraDataSize -= 12;
|
||||
@ -275,118 +254,108 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!tsmf_ffmpeg_init_context(decoder))
|
||||
if(!tsmf_ffmpeg_init_context(decoder))
|
||||
return FALSE;
|
||||
if (!tsmf_ffmpeg_init_stream(decoder, media_type))
|
||||
if(!tsmf_ffmpeg_init_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
if (!tsmf_ffmpeg_prepare(decoder))
|
||||
if(!tsmf_ffmpeg_prepare(decoder))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
int decoded;
|
||||
int len;
|
||||
AVFrame* frame;
|
||||
AVFrame *frame;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20)
|
||||
len = avcodec_decode_video(mdecoder->codec_context, mdecoder->frame, &decoded, data, data_size);
|
||||
#else
|
||||
{
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = (BYTE*) data;
|
||||
pkt.data = (BYTE *) data;
|
||||
pkt.size = data_size;
|
||||
if (extensions & TSMM_SAMPLE_EXT_CLEANPOINT)
|
||||
if(extensions & TSMM_SAMPLE_EXT_CLEANPOINT)
|
||||
pkt.flags |= AV_PKT_FLAG_KEY;
|
||||
len = avcodec_decode_video2(mdecoder->codec_context, mdecoder->frame, &decoded, &pkt);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len < 0)
|
||||
if(len < 0)
|
||||
{
|
||||
DEBUG_WARN("data_size %d, avcodec_decode_video failed (%d)", data_size, len);
|
||||
ret = FALSE;
|
||||
}
|
||||
else if (!decoded)
|
||||
{
|
||||
DEBUG_WARN("data_size %d, no frame is decoded.", data_size);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_DVC("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d "
|
||||
"pix_fmt %d width %d height %d",
|
||||
mdecoder->frame->linesize[0], mdecoder->frame->linesize[1],
|
||||
mdecoder->frame->linesize[2], mdecoder->frame->linesize[3],
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
|
||||
mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->decoded_data = malloc(mdecoder->decoded_size);
|
||||
ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size);
|
||||
frame = avcodec_alloc_frame();
|
||||
avpicture_fill((AVPicture*) frame, mdecoder->decoded_data,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
|
||||
av_picture_copy((AVPicture*) frame, (AVPicture*) mdecoder->frame,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
|
||||
av_free(frame);
|
||||
}
|
||||
|
||||
if(!decoded)
|
||||
{
|
||||
DEBUG_WARN("data_size %d, no frame is decoded.", data_size);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_TSMF("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d "
|
||||
"pix_fmt %d width %d height %d",
|
||||
mdecoder->frame->linesize[0], mdecoder->frame->linesize[1],
|
||||
mdecoder->frame->linesize[2], mdecoder->frame->linesize[3],
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->decoded_data = malloc(mdecoder->decoded_size);
|
||||
ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size);
|
||||
frame = avcodec_alloc_frame();
|
||||
avpicture_fill((AVPicture *) frame, mdecoder->decoded_data,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
av_picture_copy((AVPicture *) frame, (AVPicture *) mdecoder->frame,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
av_free(frame);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
int len;
|
||||
int frame_size;
|
||||
UINT32 src_size;
|
||||
const BYTE* src;
|
||||
BYTE* dst;
|
||||
const BYTE *src;
|
||||
BYTE *dst;
|
||||
int dst_offset;
|
||||
|
||||
#if 0
|
||||
LLOGLN(0, ("tsmf_ffmpeg_decode_audio: data_size %d", data_size));
|
||||
int i;
|
||||
for (i = 0; i < data_size; i++)
|
||||
for(i = 0; i < data_size; i++)
|
||||
{
|
||||
LLOG(0, ("%02X ", data[i]));
|
||||
if (i % 16 == 15)
|
||||
if(i % 16 == 15)
|
||||
LLOG(0, ("\n"));
|
||||
}
|
||||
LLOG(0, ("\n"));
|
||||
#endif
|
||||
|
||||
if (mdecoder->decoded_size_max == 0)
|
||||
if(mdecoder->decoded_size_max == 0)
|
||||
mdecoder->decoded_size_max = MAX_AUDIO_FRAME_SIZE + 16;
|
||||
mdecoder->decoded_data = malloc(mdecoder->decoded_size_max);
|
||||
ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size_max);
|
||||
/* align the memory for SSE2 needs */
|
||||
dst = (BYTE*) (((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
dst = (BYTE *)(((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
dst_offset = dst - mdecoder->decoded_data;
|
||||
src = data;
|
||||
src_size = data_size;
|
||||
|
||||
while (src_size > 0)
|
||||
while(src_size > 0)
|
||||
{
|
||||
/* Ensure enough space for decoding */
|
||||
if (mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE)
|
||||
if(mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE)
|
||||
{
|
||||
mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2 + 16;
|
||||
mdecoder->decoded_data = realloc(mdecoder->decoded_data, mdecoder->decoded_size_max);
|
||||
dst = (BYTE*) (((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
if (dst - mdecoder->decoded_data != dst_offset)
|
||||
dst = (BYTE *)(((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
if(dst - mdecoder->decoded_data != dst_offset)
|
||||
{
|
||||
/* re-align the memory if the alignment has changed after realloc */
|
||||
memmove(dst, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
@ -394,72 +363,64 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UI
|
||||
}
|
||||
dst += mdecoder->decoded_size;
|
||||
}
|
||||
|
||||
frame_size = mdecoder->decoded_size_max - mdecoder->decoded_size;
|
||||
#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20)
|
||||
len = avcodec_decode_audio2(mdecoder->codec_context,
|
||||
(int16_t*) dst, &frame_size, src, src_size);
|
||||
(int16_t *) dst, &frame_size, src, src_size);
|
||||
#else
|
||||
{
|
||||
AVFrame* decoded_frame = avcodec_alloc_frame();
|
||||
AVFrame *decoded_frame = avcodec_alloc_frame();
|
||||
int got_frame = 0;
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = (BYTE*) src;
|
||||
pkt.data = (BYTE *) src;
|
||||
pkt.size = src_size;
|
||||
len = avcodec_decode_audio4(mdecoder->codec_context, decoded_frame, &got_frame, &pkt);
|
||||
|
||||
if (len >= 0 && got_frame)
|
||||
if(len >= 0 && got_frame)
|
||||
{
|
||||
frame_size = av_samples_get_buffer_size(NULL, mdecoder->codec_context->channels,
|
||||
decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1);
|
||||
decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1);
|
||||
memcpy(dst, decoded_frame->data[0], frame_size);
|
||||
}
|
||||
|
||||
av_free(decoded_frame);
|
||||
}
|
||||
#endif
|
||||
if (len <= 0 || frame_size <= 0)
|
||||
if(len <= 0 || frame_size <= 0)
|
||||
{
|
||||
DEBUG_WARN("error decoding");
|
||||
break;
|
||||
}
|
||||
|
||||
src += len;
|
||||
src_size -= len;
|
||||
mdecoder->decoded_size += frame_size;
|
||||
dst += frame_size;
|
||||
}
|
||||
|
||||
if (mdecoder->decoded_size == 0)
|
||||
if(mdecoder->decoded_size == 0)
|
||||
{
|
||||
free(mdecoder->decoded_data);
|
||||
mdecoder->decoded_data = NULL;
|
||||
}
|
||||
else if (dst_offset)
|
||||
{
|
||||
/* move the aligned decoded data to original place */
|
||||
memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
}
|
||||
|
||||
DEBUG_DVC("data_size %d decoded_size %d",
|
||||
data_size, mdecoder->decoded_size);
|
||||
|
||||
else
|
||||
if(dst_offset)
|
||||
{
|
||||
/* move the aligned decoded data to original place */
|
||||
memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
}
|
||||
DEBUG_TSMF("data_size %d decoded_size %d",
|
||||
data_size, mdecoder->decoded_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (mdecoder->decoded_data)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(mdecoder->decoded_data)
|
||||
{
|
||||
free(mdecoder->decoded_data);
|
||||
mdecoder->decoded_data = NULL;
|
||||
}
|
||||
mdecoder->decoded_size = 0;
|
||||
|
||||
switch (mdecoder->media_type)
|
||||
switch(mdecoder->media_type)
|
||||
{
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
return tsmf_ffmpeg_decode_video(decoder, data, data_size, extensions);
|
||||
@ -471,40 +432,35 @@ static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE* data, UINT32 d
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE* tsmf_ffmpeg_get_decoded_data(ITSMFDecoder* decoder, UINT32* size)
|
||||
static BYTE *tsmf_ffmpeg_get_decoded_data(ITSMFDecoder *decoder, UINT32 *size)
|
||||
{
|
||||
BYTE* buf;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
BYTE *buf;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
*size = mdecoder->decoded_size;
|
||||
buf = mdecoder->decoded_data;
|
||||
mdecoder->decoded_data = NULL;
|
||||
mdecoder->decoded_size = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder* decoder)
|
||||
static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder *decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
switch (mdecoder->codec_context->pix_fmt)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
switch(mdecoder->codec_context->pix_fmt)
|
||||
{
|
||||
case PIX_FMT_YUV420P:
|
||||
return RDP_PIXFMT_I420;
|
||||
|
||||
default:
|
||||
DEBUG_WARN("unsupported pixel format %u",
|
||||
mdecoder->codec_context->pix_fmt);
|
||||
mdecoder->codec_context->pix_fmt);
|
||||
return (UINT32) -1;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32* width, UINT32* height)
|
||||
static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder *decoder, UINT32 *width, UINT32 *height)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0)
|
||||
{
|
||||
*width = mdecoder->codec_context->width;
|
||||
*height = mdecoder->codec_context->height;
|
||||
@ -516,25 +472,21 @@ static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32* wid
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_ffmpeg_free(ITSMFDecoder* decoder)
|
||||
static void tsmf_ffmpeg_free(ITSMFDecoder *decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (mdecoder->frame)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(mdecoder->frame)
|
||||
av_free(mdecoder->frame);
|
||||
|
||||
if (mdecoder->decoded_data)
|
||||
if(mdecoder->decoded_data)
|
||||
free(mdecoder->decoded_data);
|
||||
|
||||
if (mdecoder->codec_context)
|
||||
if(mdecoder->codec_context)
|
||||
{
|
||||
if (mdecoder->prepared)
|
||||
if(mdecoder->prepared)
|
||||
avcodec_close(mdecoder->codec_context);
|
||||
if (mdecoder->codec_context->extradata)
|
||||
if(mdecoder->codec_context->extradata)
|
||||
free(mdecoder->codec_context->extradata);
|
||||
av_free(mdecoder->codec_context);
|
||||
}
|
||||
|
||||
free(decoder);
|
||||
}
|
||||
|
||||
@ -544,27 +496,22 @@ static BOOL initialized = FALSE;
|
||||
#define freerdp_tsmf_client_decoder_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry
|
||||
#endif
|
||||
|
||||
ITSMFDecoder* freerdp_tsmf_client_decoder_subsystem_entry(void)
|
||||
ITSMFDecoder *freerdp_tsmf_client_decoder_subsystem_entry(void)
|
||||
{
|
||||
TSMFFFmpegDecoder* decoder;
|
||||
|
||||
if (!initialized)
|
||||
TSMFFFmpegDecoder *decoder;
|
||||
if(!initialized)
|
||||
{
|
||||
avcodec_register_all();
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
fprintf(stderr, "TSMFDecoderEntry FFMPEG\n");
|
||||
|
||||
decoder = (TSMFFFmpegDecoder*) malloc(sizeof(TSMFFFmpegDecoder));
|
||||
decoder = (TSMFFFmpegDecoder *) malloc(sizeof(TSMFFFmpegDecoder));
|
||||
ZeroMemory(decoder, sizeof(TSMFFFmpegDecoder));
|
||||
|
||||
decoder->iface.SetFormat = tsmf_ffmpeg_set_format;
|
||||
decoder->iface.Decode = tsmf_ffmpeg_decode;
|
||||
decoder->iface.GetDecodedData = tsmf_ffmpeg_get_decoded_data;
|
||||
decoder->iface.GetDecodedFormat = tsmf_ffmpeg_get_decoded_format;
|
||||
decoder->iface.GetDecodedDimension = tsmf_ffmpeg_get_decoded_dimension;
|
||||
decoder->iface.Free = tsmf_ffmpeg_free;
|
||||
|
||||
return (ITSMFDecoder*) decoder;
|
||||
return (ITSMFDecoder *) decoder;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
# 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
|
||||
# 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,
|
||||
@ -17,26 +17,60 @@
|
||||
|
||||
define_channel_client_subsystem("tsmf" "gstreamer" "decoder")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
tsmf_gstreamer.c)
|
||||
if(NOT GSTREAMER_0_10_FOUND AND NOT GSTREAMER_1_0_FOUND)
|
||||
message(FATAL_ERROR "GStreamer library not found, but required for TSMF module.")
|
||||
elseif (GSTREAMER_0_10_FOUND AND GSTREAMER_1_0_FOUND)
|
||||
message(FATAL_ERROR "GStreamer 0.10 and GStreamer 1.0 support are mutually exclusive!")
|
||||
endif()
|
||||
|
||||
set(SRC "tsmf_gstreamer.c")
|
||||
|
||||
if (GSTREAMER_1_0_FOUND)
|
||||
set(LIBS ${GSTREAMER_1_0_LIBRARIES})
|
||||
include_directories(${GSTREAMER_1_0_INCLUDE_DIRS})
|
||||
elseif (GSTREAMER_0_10_FOUND)
|
||||
set(LIBS ${GSTREAMER_0_10_LIBRARIES})
|
||||
include_directories(${GSTREAMER_0_10_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
set(SRC ${SRC}
|
||||
tsmf_android.c)
|
||||
set(LIBS ${LIBS})
|
||||
else()
|
||||
set(XEXT_FEATURE_TYPE "RECOMMENDED")
|
||||
set(XEXT_FEATURE_PURPOSE "X11 extension")
|
||||
set(XEXT_FEATURE_DESCRIPTION "X11 core extensions")
|
||||
|
||||
find_feature(Xext ${XEXT_FEATURE_TYPE} ${XEXT_FEATURE_PURPOSE} ${XEXT_FEATURE_DESCRIPTION})
|
||||
|
||||
set(SRC ${SRC}
|
||||
tsmf_X11.c)
|
||||
set(LIBS ${LIBS} ${X11_LIBRARIES} ${XEXT_LIBRARIES})
|
||||
|
||||
if(NOT XEXT_FOUND)
|
||||
message(FATAL_ERROR "Xext library not found, but required for TSMF module.")
|
||||
else()
|
||||
add_definitions(-DWITH_XEXT=1)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS "${SRC}")
|
||||
|
||||
include_directories(..)
|
||||
include_directories(${GSTREAMER_INCLUDE_DIRS})
|
||||
|
||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE freerdp
|
||||
MODULES freerdp-utils)
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE freerdp
|
||||
MODULES freerdp-utils)
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
|
||||
${GSTREAMER_LIBRARIES}
|
||||
gstapp-0.10
|
||||
gstinterfaces-0.10
|
||||
Xrandr X11 Xext)
|
||||
${LIBS})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
|
316
channels/tsmf/client/gstreamer/tsmf_X11.c
Normal file
316
channels/tsmf/client/gstreamer/tsmf_X11.c
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Video Redirection Virtual Channel - GStreamer Decoder X11 specifics
|
||||
*
|
||||
* (C) Copyright 2014 Thincast Technologies GmbH
|
||||
* (C) Copyright 2014 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
#include <gst/video/videooverlay.h>
|
||||
#else
|
||||
#include <gst/interfaces/xoverlay.h>
|
||||
#endif
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
|
||||
#include <freerdp/channels/tsmf.h>
|
||||
|
||||
#include "tsmf_platform.h"
|
||||
#include "tsmf_constants.h"
|
||||
#include "tsmf_decoder.h"
|
||||
|
||||
#if !defined(WITH_XEXT)
|
||||
#warning "Building TSMF without shape extension support"
|
||||
#endif
|
||||
|
||||
struct X11Handle
|
||||
{
|
||||
int shmid;
|
||||
int *xfwin;
|
||||
#if defined(WITH_XEXT)
|
||||
BOOL has_shape;
|
||||
#endif
|
||||
Display *disp;
|
||||
Window subwin;
|
||||
};
|
||||
|
||||
static const char *get_shm_id()
|
||||
{
|
||||
static char shm_id[64];
|
||||
snprintf(shm_id, sizeof(shm_id), "com.freerdp.xfreerpd.tsmf_%016X", GetCurrentProcessId());
|
||||
return shm_id;
|
||||
}
|
||||
|
||||
const char *tsmf_platform_get_video_sink(void)
|
||||
{
|
||||
return "xvimagesink";
|
||||
}
|
||||
|
||||
const char *tsmf_platform_get_audio_sink(void)
|
||||
{
|
||||
return "autoaudiosink";
|
||||
}
|
||||
|
||||
int tsmf_platform_create(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
struct X11Handle *hdl;
|
||||
assert(decoder);
|
||||
assert(!decoder->platform);
|
||||
hdl = malloc(sizeof(struct X11Handle));
|
||||
|
||||
if (!hdl)
|
||||
{
|
||||
DEBUG_WARN("%s: Could not allocate handle.", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(hdl, 0, sizeof(struct X11Handle));
|
||||
decoder->platform = hdl;
|
||||
hdl->shmid = shm_open(get_shm_id(), O_RDWR, PROT_READ | PROT_WRITE);;
|
||||
|
||||
if (hdl->shmid < 0)
|
||||
{
|
||||
DEBUG_WARN("%s: failed to get access to shared memory - shmget()",
|
||||
__func__);
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
hdl->xfwin = mmap(0, sizeof(void *), PROT_READ | PROT_WRITE, MAP_SHARED, hdl->shmid, 0);
|
||||
|
||||
if (hdl->xfwin == (int *)-1)
|
||||
{
|
||||
DEBUG_WARN("%s: shmat failed!", __func__);
|
||||
return -3;
|
||||
}
|
||||
|
||||
hdl->disp = XOpenDisplay(NULL);
|
||||
|
||||
if (!hdl->disp)
|
||||
{
|
||||
DEBUG_WARN("Failed to open display");
|
||||
return -4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_platform_set_format(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
|
||||
if (decoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
|
||||
{
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
assert(decoder->pipe);
|
||||
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe));
|
||||
|
||||
if (!bus)
|
||||
{
|
||||
DEBUG_WARN("gst_pipeline_get_bus failed!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_platform_free(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
struct X11Handle *hdl = decoder->platform;
|
||||
|
||||
if (!hdl)
|
||||
return -1;
|
||||
|
||||
if (hdl->disp)
|
||||
XCloseDisplay(hdl->disp);
|
||||
|
||||
if (hdl->xfwin)
|
||||
munmap(0, sizeof(void *));
|
||||
|
||||
if (hdl->shmid >= 0)
|
||||
close(hdl->shmid);
|
||||
|
||||
free(hdl);
|
||||
decoder->platform = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_window_create(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
|
||||
{
|
||||
decoder->ready = TRUE;
|
||||
return -3;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink);
|
||||
#else
|
||||
GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink);
|
||||
#endif
|
||||
struct X11Handle *hdl = (struct X11Handle *)decoder->platform;
|
||||
assert(decoder);
|
||||
assert(hdl);
|
||||
|
||||
if (!hdl->subwin)
|
||||
{
|
||||
int event, error;
|
||||
hdl->subwin = XCreateSimpleWindow(hdl->disp, *(int *)hdl->xfwin, 0, 0, 1, 1, 0, 0, 0);
|
||||
|
||||
if (!hdl->subwin)
|
||||
{
|
||||
DEBUG_WARN("Could not create subwindow!");
|
||||
}
|
||||
|
||||
XMapWindow(hdl->disp, hdl->subwin);
|
||||
XSync(hdl->disp, FALSE);
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
gst_video_overlay_set_window_handle(overlay, hdl->subwin);
|
||||
#else
|
||||
gst_x_overlay_set_window_handle(overlay, hdl->subwin);
|
||||
#endif
|
||||
decoder->ready = TRUE;
|
||||
#if defined(WITH_XEXT)
|
||||
hdl->has_shape = XShapeQueryExtension(hdl->disp, &event, &error);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
gst_video_overlay_handle_events(overlay, TRUE);
|
||||
#else
|
||||
gst_x_overlay_handle_events(overlay, TRUE);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width,
|
||||
int height, int nr_rects, RDP_RECT *rects)
|
||||
{
|
||||
if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
|
||||
return -3;
|
||||
else
|
||||
{
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink);
|
||||
#else
|
||||
GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink);
|
||||
#endif
|
||||
struct X11Handle *hdl = (struct X11Handle *)decoder->platform;
|
||||
DEBUG_TSMF("resize: x=%d, y=%d, w=%d, h=%d", x, y, width, height);
|
||||
assert(decoder);
|
||||
assert(hdl);
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
|
||||
if (!gst_video_overlay_set_render_rectangle(overlay, 0, 0, width, height))
|
||||
{
|
||||
DEBUG_WARN("Could not resize overlay!");
|
||||
}
|
||||
|
||||
gst_video_overlay_expose(overlay);
|
||||
#else
|
||||
if (!gst_x_overlay_set_render_rectangle(overlay, 0, 0, width, height))
|
||||
{
|
||||
DEBUG_WARN("Could not resize overlay!");
|
||||
}
|
||||
|
||||
gst_x_overlay_expose(overlay);
|
||||
#endif
|
||||
|
||||
if (hdl->subwin)
|
||||
{
|
||||
XMoveResizeWindow(hdl->disp, hdl->subwin, x, y, width, height);
|
||||
#if defined(WITH_XEXT)
|
||||
|
||||
if (hdl->has_shape)
|
||||
{
|
||||
int i;
|
||||
XRectangle *xrects = calloc(nr_rects, sizeof(XRectangle));
|
||||
|
||||
for (i=0; i<nr_rects; i++)
|
||||
{
|
||||
xrects[i].x = rects[i].x - x;
|
||||
xrects[i].y = rects[i].y - y;
|
||||
xrects[i].width = rects[i].width;
|
||||
xrects[i].height = rects[i].height;
|
||||
}
|
||||
|
||||
XShapeCombineRectangles(hdl->disp, hdl->subwin, ShapeBounding, x, y, xrects, nr_rects, ShapeSet, 0);
|
||||
free(xrects);
|
||||
}
|
||||
|
||||
#endif
|
||||
XSync(hdl->disp, FALSE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int tsmf_window_pause(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_window_resume(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_window_destroy(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
struct X11Handle *hdl = (struct X11Handle *)decoder->platform;
|
||||
decoder->ready = FALSE;
|
||||
|
||||
if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
|
||||
return -3;
|
||||
|
||||
assert(decoder);
|
||||
assert(hdl);
|
||||
|
||||
if (hdl->subwin)
|
||||
{
|
||||
XDestroyWindow(hdl->disp, hdl->subwin);
|
||||
XSync(hdl->disp, FALSE);
|
||||
}
|
||||
|
||||
hdl->subwin = 0;
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
83
channels/tsmf/client/gstreamer/tsmf_platform.h
Normal file
83
channels/tsmf/client/gstreamer/tsmf_platform.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Video Redirection Virtual Channel - GStreamer Decoder
|
||||
* platform specific functions
|
||||
*
|
||||
* (C) Copyright 2014 Thincast Technologies GmbH
|
||||
* (C) Copyright 2014 Armin Novak <armin.novak@thincast.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _TSMF_PLATFORM_H_
|
||||
#define _TSMF_PLATFORM_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <tsmf_decoder.h>
|
||||
|
||||
typedef struct _TSMFGstreamerDecoder
|
||||
{
|
||||
ITSMFDecoder iface;
|
||||
|
||||
int media_type; /* TSMF_MAJOR_TYPE_AUDIO or TSMF_MAJOR_TYPE_VIDEO */
|
||||
|
||||
gint64 duration;
|
||||
|
||||
GstState state;
|
||||
GstCaps *gst_caps;
|
||||
|
||||
GstElement *pipe;
|
||||
GstElement *src;
|
||||
GstElement *outsink;
|
||||
GstElement *volume;
|
||||
|
||||
BOOL ready;
|
||||
BOOL paused;
|
||||
UINT64 last_sample_end_time;
|
||||
|
||||
double gstVolume;
|
||||
BOOL gstMuted;
|
||||
|
||||
int pipeline_start_time_valid; /* We've set the start time and have not reset the pipeline */
|
||||
int shutdown; /* The decoder stream is shutting down */
|
||||
|
||||
void *platform;
|
||||
|
||||
BOOL (*ack_cb)(void *,BOOL);
|
||||
void (*sync_cb)(void *);
|
||||
void *stream;
|
||||
|
||||
} TSMFGstreamerDecoder;
|
||||
|
||||
const char *get_type(TSMFGstreamerDecoder *mdecoder);
|
||||
|
||||
const char *tsmf_platform_get_video_sink(void);
|
||||
const char *tsmf_platform_get_audio_sink(void);
|
||||
|
||||
int tsmf_platform_create(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_set_format(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_free(TSMFGstreamerDecoder *decoder);
|
||||
|
||||
int tsmf_window_create(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y,
|
||||
int width, int height, int nr_rect, RDP_RECT *visible);
|
||||
int tsmf_window_destroy(TSMFGstreamerDecoder *decoder);
|
||||
|
||||
int tsmf_window_pause(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_window_resume(TSMFGstreamerDecoder *decoder);
|
||||
|
||||
BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder);
|
||||
void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder *mdecoder);
|
||||
|
||||
#endif
|
@ -37,75 +37,70 @@ typedef struct _TSMFPulseAudioDevice
|
||||
ITSMFAudioDevice iface;
|
||||
|
||||
char device[32];
|
||||
pa_threaded_mainloop* mainloop;
|
||||
pa_context* context;
|
||||
pa_threaded_mainloop *mainloop;
|
||||
pa_context *context;
|
||||
pa_sample_spec sample_spec;
|
||||
pa_stream* stream;
|
||||
pa_stream *stream;
|
||||
} TSMFPulseAudioDevice;
|
||||
|
||||
static void tsmf_pulse_context_state_callback(pa_context* context, void* userdata)
|
||||
static void tsmf_pulse_context_state_callback(pa_context *context, void *userdata)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata;
|
||||
pa_context_state_t state;
|
||||
|
||||
state = pa_context_get_state(context);
|
||||
switch (state)
|
||||
switch(state)
|
||||
{
|
||||
case PA_CONTEXT_READY:
|
||||
DEBUG_DVC("PA_CONTEXT_READY");
|
||||
DEBUG_TSMF("PA_CONTEXT_READY");
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
case PA_CONTEXT_FAILED:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
DEBUG_DVC("state %d", (int)state);
|
||||
DEBUG_TSMF("state %d", (int)state);
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_DVC("state %d", (int)state);
|
||||
DEBUG_TSMF("state %d", (int)state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse)
|
||||
static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice *pulse)
|
||||
{
|
||||
pa_context_state_t state;
|
||||
|
||||
if (!pulse->context)
|
||||
if(!pulse->context)
|
||||
return FALSE;
|
||||
|
||||
if (pa_context_connect(pulse->context, NULL, 0, NULL))
|
||||
if(pa_context_connect(pulse->context, NULL, 0, NULL))
|
||||
{
|
||||
DEBUG_WARN("pa_context_connect failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
|
||||
if(pa_threaded_mainloop_start(pulse->mainloop) < 0)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_WARN("pa_threaded_mainloop_start failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
for (;;)
|
||||
for(;;)
|
||||
{
|
||||
state = pa_context_get_state(pulse->context);
|
||||
if (state == PA_CONTEXT_READY)
|
||||
if(state == PA_CONTEXT_READY)
|
||||
break;
|
||||
if (!PA_CONTEXT_IS_GOOD(state))
|
||||
if(!PA_CONTEXT_IS_GOOD(state))
|
||||
{
|
||||
DEBUG_DVC("bad context state (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
DEBUG_TSMF("bad context state (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
if (state == PA_CONTEXT_READY)
|
||||
if(state == PA_CONTEXT_READY)
|
||||
{
|
||||
DEBUG_DVC("connected");
|
||||
DEBUG_TSMF("connected");
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@ -115,166 +110,150 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse)
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_open(ITSMFAudioDevice* audio, const char* device)
|
||||
static BOOL tsmf_pulse_open(ITSMFAudioDevice *audio, const char *device)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
if (device)
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
if(device)
|
||||
{
|
||||
strcpy(pulse->device, device);
|
||||
}
|
||||
|
||||
pulse->mainloop = pa_threaded_mainloop_new();
|
||||
if (!pulse->mainloop)
|
||||
if(!pulse->mainloop)
|
||||
{
|
||||
DEBUG_WARN("pa_threaded_mainloop_new failed");
|
||||
return FALSE;
|
||||
}
|
||||
pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
|
||||
if (!pulse->context)
|
||||
if(!pulse->context)
|
||||
{
|
||||
DEBUG_WARN("pa_context_new failed");
|
||||
return FALSE;
|
||||
}
|
||||
pa_context_set_state_callback(pulse->context, tsmf_pulse_context_state_callback, pulse);
|
||||
if (tsmf_pulse_connect(pulse))
|
||||
if(tsmf_pulse_connect(pulse))
|
||||
{
|
||||
DEBUG_WARN("tsmf_pulse_connect failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DEBUG_DVC("open device %s", pulse->device);
|
||||
DEBUG_TSMF("open device %s", pulse->device);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void tsmf_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata)
|
||||
static void tsmf_pulse_stream_success_callback(pa_stream *stream, int success, void *userdata)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata;
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
}
|
||||
|
||||
static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice* pulse, pa_operation* operation)
|
||||
static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice *pulse, pa_operation *operation)
|
||||
{
|
||||
if (operation == NULL)
|
||||
if(operation == NULL)
|
||||
return;
|
||||
while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
|
||||
while(pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
|
||||
{
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
pa_operation_unref(operation);
|
||||
}
|
||||
|
||||
static void tsmf_pulse_stream_state_callback(pa_stream* stream, void* userdata)
|
||||
static void tsmf_pulse_stream_state_callback(pa_stream *stream, void *userdata)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata;
|
||||
pa_stream_state_t state;
|
||||
|
||||
state = pa_stream_get_state(stream);
|
||||
switch (state)
|
||||
switch(state)
|
||||
{
|
||||
case PA_STREAM_READY:
|
||||
DEBUG_DVC("PA_STREAM_READY");
|
||||
pa_threaded_mainloop_signal (pulse->mainloop, 0);
|
||||
DEBUG_TSMF("PA_STREAM_READY");
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
DEBUG_DVC("state %d", (int)state);
|
||||
pa_threaded_mainloop_signal (pulse->mainloop, 0);
|
||||
DEBUG_TSMF("state %d", (int)state);
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_DVC("state %d", (int)state);
|
||||
DEBUG_TSMF("state %d", (int)state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata)
|
||||
static void tsmf_pulse_stream_request_callback(pa_stream *stream, size_t length, void *userdata)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
|
||||
|
||||
DEBUG_DVC("%d", (int) length);
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata;
|
||||
DEBUG_TSMF("%d", (int) length);
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice* pulse)
|
||||
static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice *pulse)
|
||||
{
|
||||
if (!pulse->context || !pulse->stream)
|
||||
if(!pulse->context || !pulse->stream)
|
||||
return FALSE;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
DEBUG_TSMF("");
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
pa_stream_set_write_callback(pulse->stream, NULL, NULL);
|
||||
tsmf_pulse_wait_for_operation(pulse,
|
||||
pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
|
||||
pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
|
||||
pa_stream_disconnect(pulse->stream);
|
||||
pa_stream_unref(pulse->stream);
|
||||
pulse->stream = NULL;
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse)
|
||||
static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse)
|
||||
{
|
||||
pa_stream_state_t state;
|
||||
pa_buffer_attr buffer_attr = { 0 };
|
||||
|
||||
if (!pulse->context)
|
||||
if(!pulse->context)
|
||||
return FALSE;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
DEBUG_TSMF("");
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
pulse->stream = pa_stream_new(pulse->context, "freerdp",
|
||||
&pulse->sample_spec, NULL);
|
||||
if (!pulse->stream)
|
||||
&pulse->sample_spec, NULL);
|
||||
if(!pulse->stream)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_WARN("pa_stream_new failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
pa_stream_set_state_callback(pulse->stream,
|
||||
tsmf_pulse_stream_state_callback, pulse);
|
||||
tsmf_pulse_stream_state_callback, pulse);
|
||||
pa_stream_set_write_callback(pulse->stream,
|
||||
tsmf_pulse_stream_request_callback, pulse);
|
||||
tsmf_pulse_stream_request_callback, pulse);
|
||||
buffer_attr.maxlength = pa_usec_to_bytes(500000, &pulse->sample_spec);
|
||||
buffer_attr.tlength = pa_usec_to_bytes(250000, &pulse->sample_spec);
|
||||
buffer_attr.prebuf = (UINT32) -1;
|
||||
buffer_attr.minreq = (UINT32) -1;
|
||||
buffer_attr.fragsize = (UINT32) -1;
|
||||
if (pa_stream_connect_playback(pulse->stream,
|
||||
pulse->device[0] ? pulse->device : NULL, &buffer_attr,
|
||||
PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE,
|
||||
NULL, NULL) < 0)
|
||||
if(pa_stream_connect_playback(pulse->stream,
|
||||
pulse->device[0] ? pulse->device : NULL, &buffer_attr,
|
||||
PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE,
|
||||
NULL, NULL) < 0)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_WARN("pa_stream_connect_playback failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
for(;;)
|
||||
{
|
||||
state = pa_stream_get_state(pulse->stream);
|
||||
if (state == PA_STREAM_READY)
|
||||
if(state == PA_STREAM_READY)
|
||||
break;
|
||||
if (!PA_STREAM_IS_GOOD(state))
|
||||
if(!PA_STREAM_IS_GOOD(state))
|
||||
{
|
||||
DEBUG_WARN("bad stream state (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
if (state == PA_STREAM_READY)
|
||||
if(state == PA_STREAM_READY)
|
||||
{
|
||||
DEBUG_DVC("connected");
|
||||
DEBUG_TSMF("connected");
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@ -284,105 +263,93 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse)
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_set_format(ITSMFAudioDevice* audio,
|
||||
UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample)
|
||||
static BOOL tsmf_pulse_set_format(ITSMFAudioDevice *audio,
|
||||
UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
DEBUG_DVC("sample_rate %d channels %d bits_per_sample %d",
|
||||
sample_rate, channels, bits_per_sample);
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
DEBUG_TSMF("sample_rate %d channels %d bits_per_sample %d",
|
||||
sample_rate, channels, bits_per_sample);
|
||||
pulse->sample_spec.rate = sample_rate;
|
||||
pulse->sample_spec.channels = channels;
|
||||
pulse->sample_spec.format = PA_SAMPLE_S16LE;
|
||||
|
||||
return tsmf_pulse_open_stream(pulse);
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size)
|
||||
static BOOL tsmf_pulse_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
BYTE* src;
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
BYTE *src;
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
DEBUG_DVC("data_size %d", data_size);
|
||||
|
||||
if (pulse->stream)
|
||||
DEBUG_TSMF("data_size %d", data_size);
|
||||
if(pulse->stream)
|
||||
{
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
|
||||
src = data;
|
||||
while (data_size > 0)
|
||||
while(data_size > 0)
|
||||
{
|
||||
while ((len = pa_stream_writable_size(pulse->stream)) == 0)
|
||||
while((len = pa_stream_writable_size(pulse->stream)) == 0)
|
||||
{
|
||||
DEBUG_DVC("waiting");
|
||||
DEBUG_TSMF("waiting");
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
if (len < 0)
|
||||
if(len < 0)
|
||||
break;
|
||||
if (len > data_size)
|
||||
if(len > data_size)
|
||||
len = data_size;
|
||||
ret = pa_stream_write(pulse->stream, src, len, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
if (ret < 0)
|
||||
if(ret < 0)
|
||||
{
|
||||
DEBUG_DVC("pa_stream_write failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
DEBUG_TSMF("pa_stream_write failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
src += len;
|
||||
data_size -= len;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
}
|
||||
free(data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice* audio)
|
||||
static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice *audio)
|
||||
{
|
||||
pa_usec_t usec;
|
||||
UINT64 latency = 0;
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
if (pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0)
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
if(pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0)
|
||||
{
|
||||
latency = ((UINT64)usec) * 10LL;
|
||||
}
|
||||
return latency;
|
||||
}
|
||||
|
||||
static void tsmf_pulse_flush(ITSMFAudioDevice* audio)
|
||||
static void tsmf_pulse_flush(ITSMFAudioDevice *audio)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
tsmf_pulse_wait_for_operation(pulse,
|
||||
pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
|
||||
pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
}
|
||||
|
||||
static void tsmf_pulse_free(ITSMFAudioDevice* audio)
|
||||
static void tsmf_pulse_free(ITSMFAudioDevice *audio)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
DEBUG_TSMF("");
|
||||
tsmf_pulse_close_stream(pulse);
|
||||
if (pulse->mainloop)
|
||||
if(pulse->mainloop)
|
||||
{
|
||||
pa_threaded_mainloop_stop(pulse->mainloop);
|
||||
}
|
||||
if (pulse->context)
|
||||
if(pulse->context)
|
||||
{
|
||||
pa_context_disconnect(pulse->context);
|
||||
pa_context_unref(pulse->context);
|
||||
pulse->context = NULL;
|
||||
}
|
||||
if (pulse->mainloop)
|
||||
if(pulse->mainloop)
|
||||
{
|
||||
pa_threaded_mainloop_free(pulse->mainloop);
|
||||
pulse->mainloop = NULL;
|
||||
@ -394,20 +361,17 @@ static void tsmf_pulse_free(ITSMFAudioDevice* audio)
|
||||
#define freerdp_tsmf_client_audio_subsystem_entry pulse_freerdp_tsmf_client_audio_subsystem_entry
|
||||
#endif
|
||||
|
||||
ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void)
|
||||
ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse;
|
||||
|
||||
pulse = (TSMFPulseAudioDevice*) malloc(sizeof(TSMFPulseAudioDevice));
|
||||
TSMFPulseAudioDevice *pulse;
|
||||
pulse = (TSMFPulseAudioDevice *) malloc(sizeof(TSMFPulseAudioDevice));
|
||||
ZeroMemory(pulse, sizeof(TSMFPulseAudioDevice));
|
||||
|
||||
pulse->iface.Open = tsmf_pulse_open;
|
||||
pulse->iface.SetFormat = tsmf_pulse_set_format;
|
||||
pulse->iface.Play = tsmf_pulse_play;
|
||||
pulse->iface.GetLatency = tsmf_pulse_get_latency;
|
||||
pulse->iface.Flush = tsmf_pulse_flush;
|
||||
pulse->iface.Free = tsmf_pulse_free;
|
||||
|
||||
return (ITSMFAudioDevice*) pulse;
|
||||
return (ITSMFAudioDevice *) pulse;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
typedef struct _TSMFMediaTypeMap
|
||||
{
|
||||
BYTE guid[16];
|
||||
const char* name;
|
||||
const char *name;
|
||||
int type;
|
||||
} TSMFMediaTypeMap;
|
||||
|
||||
@ -259,24 +259,23 @@ static const TSMFMediaTypeMap tsmf_format_type_map[] =
|
||||
}
|
||||
};
|
||||
|
||||
static void tsmf_print_guid(const BYTE* guid)
|
||||
static void tsmf_print_guid(const BYTE *guid)
|
||||
{
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
#ifdef WITH_DEBUG_TSMF
|
||||
int i;
|
||||
|
||||
for (i = 3; i >= 0; i--)
|
||||
for(i = 3; i >= 0; i--)
|
||||
fprintf(stderr, "%02X", guid[i]);
|
||||
fprintf(stderr, "-");
|
||||
for (i = 5; i >= 4; i--)
|
||||
for(i = 5; i >= 4; i--)
|
||||
fprintf(stderr, "%02X", guid[i]);
|
||||
fprintf(stderr, "-");
|
||||
for (i = 7; i >= 6; i--)
|
||||
for(i = 7; i >= 6; i--)
|
||||
fprintf(stderr, "%02X", guid[i]);
|
||||
fprintf(stderr, "-");
|
||||
for (i = 8; i < 16; i++)
|
||||
for(i = 8; i < 16; i++)
|
||||
{
|
||||
fprintf(stderr, "%02X", guid[i]);
|
||||
if (i == 9)
|
||||
if(i == 9)
|
||||
fprintf(stderr, "-");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
@ -284,34 +283,29 @@ static void tsmf_print_guid(const BYTE* guid)
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/dd318229.aspx */
|
||||
static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s, BOOL bypass)
|
||||
static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wStream *s, BOOL bypass)
|
||||
{
|
||||
UINT32 biSize;
|
||||
UINT32 biWidth;
|
||||
UINT32 biHeight;
|
||||
|
||||
Stream_Read_UINT32(s, biSize);
|
||||
Stream_Read_UINT32(s, biWidth);
|
||||
Stream_Read_UINT32(s, biHeight);
|
||||
Stream_Seek(s, 28);
|
||||
|
||||
if (mediatype->Width == 0)
|
||||
if(mediatype->Width == 0)
|
||||
mediatype->Width = biWidth;
|
||||
if (mediatype->Height == 0)
|
||||
if(mediatype->Height == 0)
|
||||
mediatype->Height = biHeight;
|
||||
/* Assume there will be no color table for video? */
|
||||
|
||||
if (bypass && biSize > 40)
|
||||
if(bypass && biSize > 40)
|
||||
Stream_Seek(s, biSize - 40);
|
||||
|
||||
return (bypass ? biSize : 40);
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/dd407326.aspx */
|
||||
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE *mediatype, wStream *s)
|
||||
{
|
||||
UINT64 AvgTimePerFrame;
|
||||
|
||||
/* VIDEOINFOHEADER2.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */
|
||||
Stream_Seek_UINT32(s);
|
||||
Stream_Seek_UINT32(s);
|
||||
@ -329,25 +323,23 @@ static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, wSt
|
||||
mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL);
|
||||
/* Remaining fields before bmiHeader */
|
||||
Stream_Seek(s, 24);
|
||||
|
||||
return 72;
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/dd390700.aspx */
|
||||
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wStream *s)
|
||||
{
|
||||
/*
|
||||
typedef struct tagVIDEOINFOHEADER {
|
||||
RECT rcSource; //16
|
||||
RECT rcTarget; //16 32
|
||||
DWORD dwBitRate; //4 36
|
||||
DWORD dwBitErrorRate; //4 40
|
||||
REFERENCE_TIME AvgTimePerFrame; //8 48
|
||||
BITMAPINFOHEADER bmiHeader;
|
||||
} VIDEOINFOHEADER;
|
||||
*/
|
||||
/*
|
||||
typedef struct tagVIDEOINFOHEADER {
|
||||
RECT rcSource; //16
|
||||
RECT rcTarget; //16 32
|
||||
DWORD dwBitRate; //4 36
|
||||
DWORD dwBitErrorRate; //4 40
|
||||
REFERENCE_TIME AvgTimePerFrame; //8 48
|
||||
BITMAPINFOHEADER bmiHeader;
|
||||
} VIDEOINFOHEADER;
|
||||
*/
|
||||
UINT64 AvgTimePerFrame;
|
||||
|
||||
/* VIDEOINFOHEADER.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */
|
||||
Stream_Seek_UINT32(s);
|
||||
Stream_Seek_UINT32(s);
|
||||
@ -363,76 +355,66 @@ typedef struct tagVIDEOINFOHEADER {
|
||||
Stream_Read_UINT64(s, AvgTimePerFrame);
|
||||
mediatype->SamplesPerSecond.Numerator = 1000000;
|
||||
mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL);
|
||||
|
||||
return 48;
|
||||
}
|
||||
|
||||
BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE *mediatype, wStream *s)
|
||||
{
|
||||
int i;
|
||||
UINT32 cbFormat;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
memset(mediatype, 0, sizeof(TS_AM_MEDIA_TYPE));
|
||||
|
||||
/* MajorType */
|
||||
DEBUG_DVC("MajorType:");
|
||||
DEBUG_TSMF("MajorType:");
|
||||
tsmf_print_guid(Stream_Pointer(s));
|
||||
for (i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++)
|
||||
for(i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++)
|
||||
{
|
||||
if (memcmp(tsmf_major_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
if(memcmp(tsmf_major_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
break;
|
||||
}
|
||||
mediatype->MajorType = tsmf_major_type_map[i].type;
|
||||
if (mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN)
|
||||
if(mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN)
|
||||
ret = FALSE;
|
||||
DEBUG_DVC("MajorType %s", tsmf_major_type_map[i].name);
|
||||
DEBUG_TSMF("MajorType %s", tsmf_major_type_map[i].name);
|
||||
Stream_Seek(s, 16);
|
||||
|
||||
/* SubType */
|
||||
DEBUG_DVC("SubType:");
|
||||
DEBUG_TSMF("SubType:");
|
||||
tsmf_print_guid(Stream_Pointer(s));
|
||||
for (i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++)
|
||||
for(i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++)
|
||||
{
|
||||
if (memcmp(tsmf_sub_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
if(memcmp(tsmf_sub_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
break;
|
||||
}
|
||||
mediatype->SubType = tsmf_sub_type_map[i].type;
|
||||
if (mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN)
|
||||
if(mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN)
|
||||
ret = FALSE;
|
||||
DEBUG_DVC("SubType %s", tsmf_sub_type_map[i].name);
|
||||
DEBUG_TSMF("SubType %s", tsmf_sub_type_map[i].name);
|
||||
Stream_Seek(s, 16);
|
||||
|
||||
/* bFixedSizeSamples, bTemporalCompression, SampleSize */
|
||||
Stream_Seek(s, 12);
|
||||
|
||||
/* FormatType */
|
||||
DEBUG_DVC("FormatType:");
|
||||
DEBUG_TSMF("FormatType:");
|
||||
tsmf_print_guid(Stream_Pointer(s));
|
||||
for (i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++)
|
||||
for(i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++)
|
||||
{
|
||||
if (memcmp(tsmf_format_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
if(memcmp(tsmf_format_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
break;
|
||||
}
|
||||
mediatype->FormatType = tsmf_format_type_map[i].type;
|
||||
if (mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN)
|
||||
if(mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN)
|
||||
ret = FALSE;
|
||||
DEBUG_DVC("FormatType %s", tsmf_format_type_map[i].name);
|
||||
DEBUG_TSMF("FormatType %s", tsmf_format_type_map[i].name);
|
||||
Stream_Seek(s, 16);
|
||||
|
||||
/* cbFormat */
|
||||
Stream_Read_UINT32(s, cbFormat);
|
||||
DEBUG_DVC("cbFormat %d", cbFormat);
|
||||
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
DEBUG_TSMF("cbFormat %d", cbFormat);
|
||||
#ifdef WITH_DEBUG_TSMF
|
||||
winpr_HexDump(Stream_Pointer(s), cbFormat);
|
||||
#endif
|
||||
|
||||
switch (mediatype->FormatType)
|
||||
switch(mediatype->FormatType)
|
||||
{
|
||||
case TSMF_FORMAT_TYPE_MFVIDEOFORMAT:
|
||||
/* http://msdn.microsoft.com/en-us/library/aa473808.aspx */
|
||||
|
||||
Stream_Seek(s, 8); /* dwSize and ? */
|
||||
Stream_Read_UINT32(s, mediatype->Width); /* videoInfo.dwWidth */
|
||||
Stream_Read_UINT32(s, mediatype->Height); /* videoInfo.dwHeight */
|
||||
@ -443,17 +425,14 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
Stream_Seek(s, 80);
|
||||
Stream_Read_UINT32(s, mediatype->BitRate); /* compressedInfo.AvgBitrate */
|
||||
Stream_Seek(s, 36);
|
||||
|
||||
if (cbFormat > 176)
|
||||
if(cbFormat > 176)
|
||||
{
|
||||
mediatype->ExtraDataSize = cbFormat - 176;
|
||||
mediatype->ExtraData = Stream_Pointer(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_FORMAT_TYPE_WAVEFORMATEX:
|
||||
/* http://msdn.microsoft.com/en-us/library/dd757720.aspx */
|
||||
|
||||
Stream_Seek_UINT16(s);
|
||||
Stream_Read_UINT16(s, mediatype->Channels);
|
||||
Stream_Read_UINT32(s, mediatype->SamplesPerSecond.Numerator);
|
||||
@ -463,66 +442,55 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
Stream_Read_UINT16(s, mediatype->BlockAlign);
|
||||
Stream_Read_UINT16(s, mediatype->BitsPerSample);
|
||||
Stream_Read_UINT16(s, mediatype->ExtraDataSize);
|
||||
if (mediatype->ExtraDataSize > 0)
|
||||
if(mediatype->ExtraDataSize > 0)
|
||||
mediatype->ExtraData = Stream_Pointer(s);
|
||||
|
||||
break;
|
||||
|
||||
case TSMF_FORMAT_TYPE_MPEG1VIDEOINFO:
|
||||
/* http://msdn.microsoft.com/en-us/library/dd390700.aspx */
|
||||
|
||||
i = tsmf_codec_parse_VIDEOINFOHEADER(mediatype, s);
|
||||
i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, TRUE);
|
||||
if (cbFormat > i)
|
||||
if(cbFormat > i)
|
||||
{
|
||||
mediatype->ExtraDataSize = cbFormat - i;
|
||||
mediatype->ExtraData = Stream_Pointer(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_FORMAT_TYPE_MPEG2VIDEOINFO:
|
||||
/* http://msdn.microsoft.com/en-us/library/dd390707.aspx */
|
||||
|
||||
i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s);
|
||||
i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, TRUE);
|
||||
if (cbFormat > i)
|
||||
if(cbFormat > i)
|
||||
{
|
||||
mediatype->ExtraDataSize = cbFormat - i;
|
||||
mediatype->ExtraData = Stream_Pointer(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_FORMAT_TYPE_VIDEOINFO2:
|
||||
i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s);
|
||||
i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, FALSE);
|
||||
if (cbFormat > i)
|
||||
if(cbFormat > i)
|
||||
{
|
||||
mediatype->ExtraDataSize = cbFormat - i;
|
||||
mediatype->ExtraData = Stream_Pointer(s);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (mediatype->SamplesPerSecond.Numerator == 0)
|
||||
if(mediatype->SamplesPerSecond.Numerator == 0)
|
||||
mediatype->SamplesPerSecond.Numerator = 1;
|
||||
if (mediatype->SamplesPerSecond.Denominator == 0)
|
||||
if(mediatype->SamplesPerSecond.Denominator == 0)
|
||||
mediatype->SamplesPerSecond.Denominator = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL tsmf_codec_check_media_type(wStream* s)
|
||||
BOOL tsmf_codec_check_media_type(wStream *s)
|
||||
{
|
||||
BYTE* m;
|
||||
BYTE *m;
|
||||
BOOL ret;
|
||||
TS_AM_MEDIA_TYPE mediatype;
|
||||
|
||||
Stream_GetPointer(s, m);
|
||||
ret = tsmf_codec_parse_media_type(&mediatype, s);
|
||||
Stream_SetPointer(s, m);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -32,45 +32,41 @@
|
||||
#include "tsmf_constants.h"
|
||||
#include "tsmf_decoder.h"
|
||||
|
||||
static ITSMFDecoder* tsmf_load_decoder_by_name(const char* name, TS_AM_MEDIA_TYPE* media_type)
|
||||
static ITSMFDecoder *tsmf_load_decoder_by_name(const char *name, TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
ITSMFDecoder* decoder;
|
||||
ITSMFDecoder *decoder;
|
||||
TSMF_DECODER_ENTRY entry;
|
||||
|
||||
entry = (TSMF_DECODER_ENTRY) freerdp_load_channel_addin_entry("tsmf", (LPSTR) name, "decoder", 0);
|
||||
|
||||
if (entry == NULL)
|
||||
if(entry == NULL)
|
||||
return NULL;
|
||||
|
||||
decoder = entry();
|
||||
|
||||
if (decoder == NULL)
|
||||
if(decoder == NULL)
|
||||
{
|
||||
DEBUG_WARN("failed to call export function in %s", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!decoder->SetFormat(decoder, media_type))
|
||||
if(!decoder->SetFormat(decoder, media_type))
|
||||
{
|
||||
decoder->Free(decoder);
|
||||
decoder = NULL;
|
||||
}
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type)
|
||||
ITSMFDecoder *tsmf_load_decoder(const char *name, TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
ITSMFDecoder* decoder;
|
||||
|
||||
if (name)
|
||||
ITSMFDecoder *decoder = NULL;
|
||||
if(name)
|
||||
{
|
||||
decoder = tsmf_load_decoder_by_name(name, media_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(WITH_GSTREAMER_1_0) || defined(WITH_GSTREAMER_0_10)
|
||||
if(!decoder)
|
||||
decoder = tsmf_load_decoder_by_name("gstreamer", media_type);
|
||||
#endif
|
||||
#if defined(WITH_FFMPEG)
|
||||
if(!decoder)
|
||||
decoder = tsmf_load_decoder_by_name("ffmpeg", media_type);
|
||||
}
|
||||
|
||||
#endif
|
||||
return decoder;
|
||||
}
|
||||
|
@ -26,9 +26,8 @@
|
||||
typedef enum _ITSMFControlMsg
|
||||
{
|
||||
Control_Pause,
|
||||
Control_Restart,
|
||||
Control_Flush,
|
||||
Control_EndOfStream
|
||||
Control_Resume,
|
||||
Control_Stop
|
||||
} ITSMFControlMsg;
|
||||
|
||||
typedef struct _ITSMFDecoder ITSMFDecoder;
|
||||
@ -36,36 +35,40 @@ typedef struct _ITSMFDecoder ITSMFDecoder;
|
||||
struct _ITSMFDecoder
|
||||
{
|
||||
/* Set the decoder format. Return true if supported. */
|
||||
BOOL (*SetFormat) (ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type);
|
||||
BOOL (*SetFormat)(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type);
|
||||
/* Decode a sample. */
|
||||
BOOL (*Decode) (ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions);
|
||||
BOOL (*Decode)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions);
|
||||
/* Get the decoded data */
|
||||
BYTE* (*GetDecodedData) (ITSMFDecoder* decoder, UINT32* size);
|
||||
BYTE *(*GetDecodedData)(ITSMFDecoder *decoder, UINT32 *size);
|
||||
/* Get the pixel format of decoded video frame */
|
||||
UINT32 (*GetDecodedFormat) (ITSMFDecoder* decoder);
|
||||
UINT32(*GetDecodedFormat)(ITSMFDecoder *decoder);
|
||||
/* Get the width and height of decoded video frame */
|
||||
BOOL (*GetDecodedDimension) (ITSMFDecoder* decoder, UINT32* width, UINT32* height);
|
||||
BOOL (*GetDecodedDimension)(ITSMFDecoder *decoder, UINT32 *width, UINT32 *height);
|
||||
/* Free the decoder */
|
||||
void (*Free) (ITSMFDecoder * decoder);
|
||||
void (*Free)(ITSMFDecoder *decoder);
|
||||
/* Optional Contol function */
|
||||
void (*Control) (ITSMFDecoder * decoder, ITSMFControlMsg control_msg, UINT32 *arg);
|
||||
void (*Control)(ITSMFDecoder *decoder, ITSMFControlMsg control_msg, UINT32 *arg);
|
||||
/* Decode a sample with extended interface. */
|
||||
int (*DecodeEx) (ITSMFDecoder * decoder, const BYTE * data, UINT32 data_size, UINT32 extensions,
|
||||
UINT64 start_time, UINT64 end_time, UINT64 duration);
|
||||
int (*DecodeEx)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions,
|
||||
UINT64 start_time, UINT64 end_time, UINT64 duration);
|
||||
/* Get current play time */
|
||||
UINT64 (*GetRunningTime) (ITSMFDecoder * decoder);
|
||||
UINT64(*GetRunningTime)(ITSMFDecoder *decoder);
|
||||
/* Update Gstreamer Rendering Area */
|
||||
void (*UpdateRenderingArea) (ITSMFDecoder * decoder, int newX, int newY, int newWidth, int newHeight, int numRectangles, RDP_RECT *rectangles);
|
||||
void (*UpdateRenderingArea)(ITSMFDecoder *decoder, int newX, int newY, int newWidth, int newHeight, int numRectangles, RDP_RECT *rectangles);
|
||||
/* Change Gstreamer Audio Volume */
|
||||
void (*ChangeVolume) (ITSMFDecoder * decoder, UINT32 newVolume, UINT32 muted);
|
||||
void (*ChangeVolume)(ITSMFDecoder *decoder, UINT32 newVolume, UINT32 muted);
|
||||
/* Check buffer level */
|
||||
UINT32 (*BufferLevel) (ITSMFDecoder * decoder);
|
||||
BOOL (*BufferFilled)(ITSMFDecoder *decoder);
|
||||
/* Register a callback for frame ack. */
|
||||
BOOL (*SetAckFunc)(ITSMFDecoder *decoder, BOOL (*cb)(void *,BOOL), void *stream);
|
||||
/* Register a callback for stream seek detection. */
|
||||
BOOL (*SetSyncFunc)(ITSMFDecoder *decoder, void (*cb)(void *), void *stream);
|
||||
};
|
||||
|
||||
#define TSMF_DECODER_EXPORT_FUNC_NAME "TSMFDecoderEntry"
|
||||
typedef ITSMFDecoder* (*TSMF_DECODER_ENTRY) (void);
|
||||
typedef ITSMFDecoder *(*TSMF_DECODER_ENTRY)(void);
|
||||
|
||||
ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type);
|
||||
ITSMFDecoder *tsmf_load_decoder(const char *name, TS_AM_MEDIA_TYPE *media_type);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -37,21 +37,18 @@
|
||||
|
||||
#include "tsmf_ifman.h"
|
||||
|
||||
int tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 CapabilityValue;
|
||||
|
||||
Stream_Read_UINT32(ifman->input, CapabilityValue);
|
||||
DEBUG_DVC("server CapabilityValue %d", CapabilityValue);
|
||||
|
||||
DEBUG_TSMF("server CapabilityValue %d", CapabilityValue);
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 8);
|
||||
Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 v;
|
||||
@ -59,32 +56,28 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
UINT32 CapabilityType;
|
||||
UINT32 cbCapabilityLength;
|
||||
UINT32 numHostCapabilities;
|
||||
|
||||
pos = Stream_GetPosition(ifman->output);
|
||||
Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4);
|
||||
Stream_Copy(ifman->output, ifman->input, ifman->input_size);
|
||||
|
||||
Stream_SetPosition(ifman->output, pos);
|
||||
Stream_Read_UINT32(ifman->output, numHostCapabilities);
|
||||
|
||||
for (i = 0; i < numHostCapabilities; i++)
|
||||
for(i = 0; i < numHostCapabilities; i++)
|
||||
{
|
||||
Stream_Read_UINT32(ifman->output, CapabilityType);
|
||||
Stream_Read_UINT32(ifman->output, cbCapabilityLength);
|
||||
pos = Stream_GetPosition(ifman->output);
|
||||
|
||||
switch (CapabilityType)
|
||||
switch(CapabilityType)
|
||||
{
|
||||
case 1: /* Protocol version request */
|
||||
Stream_Read_UINT32(ifman->output, v);
|
||||
DEBUG_DVC("server protocol version %d", v);
|
||||
DEBUG_TSMF("server protocol version %d", v);
|
||||
break;
|
||||
case 2: /* Supported platform */
|
||||
Stream_Peek_UINT32(ifman->output, v);
|
||||
DEBUG_DVC("server supported platform %d", v);
|
||||
DEBUG_TSMF("server supported platform %d", v);
|
||||
/* Claim that we support both MF and DShow platforms. */
|
||||
Stream_Write_UINT32(ifman->output,
|
||||
MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
|
||||
MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
|
||||
break;
|
||||
default:
|
||||
DEBUG_WARN("unknown capability type %d", CapabilityType);
|
||||
@ -93,81 +86,62 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
Stream_SetPosition(ifman->output, pos + cbCapabilityLength);
|
||||
}
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_check_format_support_request(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 numMediaType;
|
||||
UINT32 PlatformCookie;
|
||||
UINT32 FormatSupported = 1;
|
||||
|
||||
Stream_Read_UINT32(ifman->input, PlatformCookie);
|
||||
Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
|
||||
Stream_Read_UINT32(ifman->input, numMediaType);
|
||||
|
||||
DEBUG_DVC("PlatformCookie %d numMediaType %d", PlatformCookie, numMediaType);
|
||||
|
||||
if (!tsmf_codec_check_media_type(ifman->input))
|
||||
DEBUG_TSMF("PlatformCookie %d numMediaType %d", PlatformCookie, numMediaType);
|
||||
if(!tsmf_codec_check_media_type(ifman->input))
|
||||
FormatSupported = 0;
|
||||
|
||||
if (FormatSupported)
|
||||
DEBUG_DVC("format ok.");
|
||||
|
||||
if(FormatSupported)
|
||||
DEBUG_TSMF("format ok.");
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 12);
|
||||
Stream_Write_UINT32(ifman->output, FormatSupported);
|
||||
Stream_Write_UINT32(ifman->output, PlatformCookie);
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_new_presentation(TSMF_IFMAN *ifman)
|
||||
{
|
||||
int status = 0;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
DEBUG_DVC("Presentation already exists");
|
||||
DEBUG_TSMF("Presentation already exists");
|
||||
ifman->output_pending = FALSE;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
status = 1;
|
||||
else
|
||||
tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int tsmf_ifman_add_stream(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_add_stream(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 StreamId;
|
||||
int status = 0;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
@ -176,41 +150,33 @@ int tsmf_ifman_add_stream(TSMF_IFMAN* ifman)
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
Stream_Seek_UINT32(ifman->input); /* numMediaType */
|
||||
stream = tsmf_stream_new(presentation, StreamId);
|
||||
|
||||
if (stream)
|
||||
if(stream)
|
||||
tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_set_topology_request(TSMF_IFMAN *ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
|
||||
DEBUG_TSMF("");
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 8);
|
||||
Stream_Write_UINT32(ifman->output, 1); /* TopologyReady */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_remove_stream(TSMF_IFMAN *ifman)
|
||||
{
|
||||
int status = 0;
|
||||
UINT32 StreamId;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
@ -218,41 +184,34 @@ int tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
|
||||
{
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
stream = tsmf_stream_find_by_id(presentation, StreamId);
|
||||
if (stream)
|
||||
if(stream)
|
||||
tsmf_stream_free(stream);
|
||||
else
|
||||
status = 1;
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
float tsmf_stream_read_float(wStream* s)
|
||||
float tsmf_stream_read_float(wStream *s)
|
||||
{
|
||||
float fValue;
|
||||
UINT32 iValue;
|
||||
|
||||
Stream_Read_UINT32(s, iValue);
|
||||
CopyMemory(&fValue, &iValue, 4);
|
||||
|
||||
return fValue;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_set_source_video_rect(TSMF_IFMAN *ifman)
|
||||
{
|
||||
int status = 0;
|
||||
float Left, Top;
|
||||
float Right, Bottom;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
|
||||
if (!presentation)
|
||||
if(!presentation)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
@ -262,144 +221,117 @@ int tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
|
||||
Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */
|
||||
Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */
|
||||
Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */
|
||||
|
||||
DEBUG_DVC("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f",
|
||||
Left, Top, Right, Bottom);
|
||||
DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f",
|
||||
Left, Top, Right, Bottom);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_shutdown_presentation(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_free(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 4);
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_stream_volume(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("on stream volume");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("on stream volume");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
UINT32 newVolume;
|
||||
UINT32 muted;
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, newVolume);
|
||||
DEBUG_DVC("on stream volume: new volume=[%d]", newVolume);
|
||||
DEBUG_TSMF("on stream volume: new volume=[%d]", newVolume);
|
||||
Stream_Read_UINT32(ifman->input, muted);
|
||||
DEBUG_DVC("on stream volume: muted=[%d]", muted);
|
||||
DEBUG_TSMF("on stream volume: muted=[%d]", muted);
|
||||
tsmf_presentation_volume_changed(presentation, newVolume, muted);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_channel_volume(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("on channel volume");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("on channel volume");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
UINT32 channelVolume;
|
||||
UINT32 changedChannel;
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, channelVolume);
|
||||
DEBUG_DVC("on channel volume: channel volume=[%d]", channelVolume);
|
||||
DEBUG_TSMF("on channel volume: channel volume=[%d]", channelVolume);
|
||||
Stream_Read_UINT32(ifman->input, changedChannel);
|
||||
DEBUG_DVC("on stream volume: changed channel=[%d]", changedChannel);
|
||||
DEBUG_TSMF("on stream volume: changed channel=[%d]", changedChannel);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_set_video_window(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_update_geometry_info(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
UINT32 numGeometryInfo;
|
||||
UINT32 Left;
|
||||
UINT32 Top;
|
||||
UINT32 Width;
|
||||
UINT32 Height;
|
||||
UINT32 cbVisibleRect;
|
||||
RDP_RECT* rects = NULL;
|
||||
RDP_RECT *rects = NULL;
|
||||
int num_rects = 0;
|
||||
int error = 0;
|
||||
int i;
|
||||
int pos;
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
|
||||
Stream_Read_UINT32(ifman->input, numGeometryInfo);
|
||||
pos = Stream_GetPosition(ifman->input);
|
||||
|
||||
Stream_Seek(ifman->input, 12); /* VideoWindowId (8 bytes), VideoWindowState (4 bytes) */
|
||||
Stream_Read_UINT32(ifman->input, Width);
|
||||
Stream_Read_UINT32(ifman->input, Height);
|
||||
Stream_Read_UINT32(ifman->input, Left);
|
||||
Stream_Read_UINT32(ifman->input, Top);
|
||||
|
||||
Stream_SetPosition(ifman->input, pos + numGeometryInfo);
|
||||
Stream_Read_UINT32(ifman->input, cbVisibleRect);
|
||||
num_rects = cbVisibleRect / 16;
|
||||
|
||||
DEBUG_DVC("numGeometryInfo %d Width %d Height %d Left %d Top %d cbVisibleRect %d num_rects %d",
|
||||
numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
|
||||
|
||||
if (presentation == NULL)
|
||||
DEBUG_TSMF("numGeometryInfo %d Width %d Height %d Left %d Top %d cbVisibleRect %d num_rects %d",
|
||||
numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
|
||||
if(presentation == NULL)
|
||||
{
|
||||
error = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_rects > 0)
|
||||
if(num_rects > 0)
|
||||
{
|
||||
rects = (RDP_RECT*) malloc(sizeof(RDP_RECT) * num_rects);
|
||||
rects = (RDP_RECT *) malloc(sizeof(RDP_RECT) * num_rects);
|
||||
ZeroMemory(rects, sizeof(RDP_RECT) * num_rects);
|
||||
|
||||
for (i = 0; i < num_rects; i++)
|
||||
for(i = 0; i < num_rects; i++)
|
||||
{
|
||||
Stream_Read_UINT16(ifman->input, rects[i].y); /* Top */
|
||||
Stream_Seek_UINT16(ifman->input);
|
||||
@ -411,44 +343,40 @@ int tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
|
||||
Stream_Seek_UINT16(ifman->input);
|
||||
rects[i].width -= rects[i].x;
|
||||
rects[i].height -= rects[i].y;
|
||||
|
||||
DEBUG_DVC("rect %d: %d %d %d %d", i,
|
||||
rects[i].x, rects[i].y, rects[i].width, rects[i].height);
|
||||
DEBUG_TSMF("rect %d: %d %d %d %d", i,
|
||||
rects[i].x, rects[i].y, rects[i].width, rects[i].height);
|
||||
}
|
||||
}
|
||||
tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects, rects);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_allocator(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_set_allocator(TSMF_IFMAN *ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_notify_preroll(TSMF_IFMAN *ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_sample(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_STREAM *stream;
|
||||
UINT32 StreamId;
|
||||
UINT64 SampleStartTime;
|
||||
UINT64 SampleEndTime;
|
||||
UINT64 ThrottleDuration;
|
||||
UINT32 SampleExtensions;
|
||||
UINT32 cbData;
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
Stream_Seek_UINT32(ifman->input); /* numSample */
|
||||
@ -458,183 +386,144 @@ int tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
|
||||
Stream_Seek_UINT32(ifman->input); /* SampleFlags */
|
||||
Stream_Read_UINT32(ifman->input, SampleExtensions);
|
||||
Stream_Read_UINT32(ifman->input, cbData);
|
||||
|
||||
DEBUG_DVC("MessageId %d StreamId %d SampleStartTime %d SampleEndTime %d "
|
||||
"ThrottleDuration %d SampleExtensions %d cbData %d",
|
||||
ifman->message_id, StreamId, (int)SampleStartTime, (int)SampleEndTime,
|
||||
(int)ThrottleDuration, SampleExtensions, cbData);
|
||||
|
||||
DEBUG_TSMF("MessageId %d StreamId %d SampleStartTime %d SampleEndTime %d "
|
||||
"ThrottleDuration %d SampleExtensions %d cbData %d",
|
||||
ifman->message_id, StreamId, (int)SampleStartTime, (int)SampleEndTime,
|
||||
(int)ThrottleDuration, SampleExtensions, cbData);
|
||||
presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
{
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
return 1;
|
||||
}
|
||||
|
||||
stream = tsmf_stream_find_by_id(presentation, StreamId);
|
||||
|
||||
if (stream == NULL)
|
||||
if(stream == NULL)
|
||||
{
|
||||
DEBUG_WARN("unknown stream id");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tsmf_stream_push_sample(stream, ifman->channel_callback,
|
||||
ifman->message_id, SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
|
||||
cbData, Stream_Pointer(ifman->input));
|
||||
|
||||
ifman->message_id, SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
|
||||
cbData, Stream_Pointer(ifman->input));
|
||||
tsmf_presentation_sync(presentation);
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_flush(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 StreamId;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
DEBUG_DVC("StreamId %d", StreamId);
|
||||
|
||||
DEBUG_TSMF("StreamId %d", StreamId);
|
||||
presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
{
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tsmf_presentation_flush(presentation);
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_end_of_stream(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 StreamId;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
stream = tsmf_stream_find_by_id(presentation, StreamId);
|
||||
if (stream)
|
||||
if(stream)
|
||||
tsmf_stream_end(stream);
|
||||
}
|
||||
DEBUG_DVC("StreamId %d", StreamId);
|
||||
|
||||
DEBUG_TSMF("StreamId %d", StreamId);
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, StreamId); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_playback_started(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_start(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_playback_paused(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
/* Added pause control so gstreamer pipeline can be paused accordingly */
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_paused(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_playback_restarted(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
/* Added restart control so gstreamer pipeline can be resumed accordingly */
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_restarted(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_playback_stopped(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_stop(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN * ifman)
|
||||
int tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN *ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
|
||||
DEBUG_TSMF("");
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_MONITORCHANGED); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -47,19 +47,19 @@ struct _TSMF_LISTENER_CALLBACK
|
||||
{
|
||||
IWTSListenerCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
IWTSPlugin *plugin;
|
||||
IWTSVirtualChannelManager *channel_mgr;
|
||||
};
|
||||
|
||||
struct _TSMF_CHANNEL_CALLBACK
|
||||
{
|
||||
IWTSVirtualChannelCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
IWTSVirtualChannel* channel;
|
||||
IWTSPlugin *plugin;
|
||||
IWTSVirtualChannelManager *channel_mgr;
|
||||
IWTSVirtualChannel *channel;
|
||||
|
||||
BYTE presentation_id[16];
|
||||
BYTE presentation_id[GUID_SIZE];
|
||||
UINT32 stream_id;
|
||||
};
|
||||
|
||||
@ -67,20 +67,19 @@ struct _TSMF_PLUGIN
|
||||
{
|
||||
IWTSPlugin iface;
|
||||
|
||||
TSMF_LISTENER_CALLBACK* listener_callback;
|
||||
TSMF_LISTENER_CALLBACK *listener_callback;
|
||||
|
||||
const char* decoder_name;
|
||||
const char* audio_name;
|
||||
const char* audio_device;
|
||||
const char *decoder_name;
|
||||
const char *audio_name;
|
||||
const char *audio_device;
|
||||
};
|
||||
|
||||
void tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
UINT32 message_id, UINT64 duration, UINT32 data_size)
|
||||
void tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback,
|
||||
UINT32 message_id, UINT64 duration, UINT32 data_size)
|
||||
{
|
||||
wStream* s;
|
||||
int status;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
wStream *s;
|
||||
int status = -1;
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
s = Stream_New(NULL, 32);
|
||||
Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY);
|
||||
Stream_Write_UINT32(s, message_id);
|
||||
@ -88,71 +87,67 @@ void tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
Stream_Write_UINT32(s, callback->stream_id); /* StreamId */
|
||||
Stream_Write_UINT64(s, duration); /* DataDuration */
|
||||
Stream_Write_UINT64(s, data_size); /* cbData */
|
||||
|
||||
DEBUG_DVC("response size %d", (int) Stream_GetPosition(s));
|
||||
status = callback->channel->Write(callback->channel, Stream_GetPosition(s), Stream_Buffer(s), NULL);
|
||||
|
||||
if (status)
|
||||
DEBUG_TSMF("response size %d", (int) Stream_GetPosition(s));
|
||||
if(!callback || !callback->channel || !callback->channel->Write)
|
||||
DEBUG_WARN("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)
|
||||
{
|
||||
DEBUG_WARN("response error %d", status);
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
BOOL tsmf_push_event(IWTSVirtualChannelCallback* pChannelCallback, wMessage* event)
|
||||
BOOL tsmf_push_event(IWTSVirtualChannelCallback *pChannelCallback, wMessage *event)
|
||||
{
|
||||
int status;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
status = callback->channel_mgr->PushEvent(callback->channel_mgr, event);
|
||||
|
||||
if (status)
|
||||
if(status)
|
||||
{
|
||||
DEBUG_WARN("response error %d", status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
UINT32 cbSize,
|
||||
BYTE* pBuffer)
|
||||
static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||
{
|
||||
int length;
|
||||
wStream* input;
|
||||
wStream* output;
|
||||
wStream *input;
|
||||
wStream *output;
|
||||
int status = -1;
|
||||
TSMF_IFMAN ifman;
|
||||
UINT32 MessageId;
|
||||
UINT32 FunctionId;
|
||||
UINT32 InterfaceId;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
UINT32 cbSize = Stream_GetRemainingLength(data);
|
||||
|
||||
/* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */
|
||||
if (cbSize < 12)
|
||||
if(cbSize < 12)
|
||||
{
|
||||
DEBUG_WARN("invalid size. cbSize=%d", cbSize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
input = Stream_New((BYTE*) pBuffer, cbSize);
|
||||
input = data;
|
||||
output = Stream_New(NULL, 256);
|
||||
Stream_Seek(output, 8);
|
||||
|
||||
Stream_Read_UINT32(input, InterfaceId);
|
||||
Stream_Read_UINT32(input, MessageId);
|
||||
Stream_Read_UINT32(input, FunctionId);
|
||||
DEBUG_DVC("cbSize=%d InterfaceId=0x%X MessageId=0x%X FunctionId=0x%X",
|
||||
cbSize, InterfaceId, MessageId, FunctionId);
|
||||
|
||||
DEBUG_TSMF("cbSize=%d InterfaceId=0x%X MessageId=0x%X FunctionId=0x%X",
|
||||
cbSize, InterfaceId, MessageId, FunctionId);
|
||||
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, 16);
|
||||
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);
|
||||
ifman.stream_id = callback->stream_id;
|
||||
ifman.message_id = MessageId;
|
||||
ifman.input = input;
|
||||
@ -160,139 +155,108 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
ifman.output = output;
|
||||
ifman.output_pending = FALSE;
|
||||
ifman.output_interface_id = InterfaceId;
|
||||
|
||||
switch (InterfaceId)
|
||||
switch(InterfaceId)
|
||||
{
|
||||
case TSMF_INTERFACE_CAPABILITIES | STREAM_ID_NONE:
|
||||
|
||||
switch (FunctionId)
|
||||
switch(FunctionId)
|
||||
{
|
||||
case RIM_EXCHANGE_CAPABILITY_REQUEST:
|
||||
status = tsmf_ifman_rim_exchange_capability_request(&ifman);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_INTERFACE_DEFAULT | STREAM_ID_PROXY:
|
||||
|
||||
switch (FunctionId)
|
||||
switch(FunctionId)
|
||||
{
|
||||
case SET_CHANNEL_PARAMS:
|
||||
memcpy(callback->presentation_id, Stream_Pointer(input), 16);
|
||||
Stream_Seek(input, 16);
|
||||
memcpy(callback->presentation_id, Stream_Pointer(input), GUID_SIZE);
|
||||
Stream_Seek(input, GUID_SIZE);
|
||||
Stream_Read_UINT32(input, callback->stream_id);
|
||||
DEBUG_DVC("SET_CHANNEL_PARAMS StreamId=%d", callback->stream_id);
|
||||
DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%d", callback->stream_id);
|
||||
ifman.output_pending = TRUE;
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case EXCHANGE_CAPABILITIES_REQ:
|
||||
status = tsmf_ifman_exchange_capability_request(&ifman);
|
||||
break;
|
||||
|
||||
case CHECK_FORMAT_SUPPORT_REQ:
|
||||
status = tsmf_ifman_check_format_support_request(&ifman);
|
||||
break;
|
||||
|
||||
case ON_NEW_PRESENTATION:
|
||||
status = tsmf_ifman_on_new_presentation(&ifman);
|
||||
break;
|
||||
|
||||
case ADD_STREAM:
|
||||
status = tsmf_ifman_add_stream(&ifman);
|
||||
break;
|
||||
|
||||
case SET_TOPOLOGY_REQ:
|
||||
status = tsmf_ifman_set_topology_request(&ifman);
|
||||
break;
|
||||
|
||||
case REMOVE_STREAM:
|
||||
status = tsmf_ifman_remove_stream(&ifman);
|
||||
break;
|
||||
|
||||
case SET_SOURCE_VIDEO_RECT:
|
||||
status = tsmf_ifman_set_source_video_rect(&ifman);
|
||||
break;
|
||||
|
||||
case SHUTDOWN_PRESENTATION_REQ:
|
||||
status = tsmf_ifman_shutdown_presentation(&ifman);
|
||||
break;
|
||||
|
||||
case ON_STREAM_VOLUME:
|
||||
status = tsmf_ifman_on_stream_volume(&ifman);
|
||||
break;
|
||||
|
||||
case ON_CHANNEL_VOLUME:
|
||||
status = tsmf_ifman_on_channel_volume(&ifman);
|
||||
break;
|
||||
|
||||
case SET_VIDEO_WINDOW:
|
||||
status = tsmf_ifman_set_video_window(&ifman);
|
||||
break;
|
||||
|
||||
case UPDATE_GEOMETRY_INFO:
|
||||
status = tsmf_ifman_update_geometry_info(&ifman);
|
||||
break;
|
||||
|
||||
case SET_ALLOCATOR:
|
||||
status = tsmf_ifman_set_allocator(&ifman);
|
||||
break;
|
||||
|
||||
case NOTIFY_PREROLL:
|
||||
status = tsmf_ifman_notify_preroll(&ifman);
|
||||
break;
|
||||
|
||||
case ON_SAMPLE:
|
||||
status = tsmf_ifman_on_sample(&ifman);
|
||||
break;
|
||||
|
||||
case ON_FLUSH:
|
||||
status = tsmf_ifman_on_flush(&ifman);
|
||||
break;
|
||||
|
||||
case ON_END_OF_STREAM:
|
||||
status = tsmf_ifman_on_end_of_stream(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_STARTED:
|
||||
status = tsmf_ifman_on_playback_started(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_PAUSED:
|
||||
status = tsmf_ifman_on_playback_paused(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_RESTARTED:
|
||||
status = tsmf_ifman_on_playback_restarted(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_STOPPED:
|
||||
status = tsmf_ifman_on_playback_stopped(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_RATE_CHANGED:
|
||||
status = tsmf_ifman_on_playback_rate_changed(&ifman);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_Free(input, FALSE);
|
||||
input = NULL;
|
||||
ifman.input = NULL;
|
||||
|
||||
if (status == -1)
|
||||
if(status == -1)
|
||||
{
|
||||
switch (FunctionId)
|
||||
switch(FunctionId)
|
||||
{
|
||||
case RIMCALL_RELEASE:
|
||||
/* [MS-RDPEXPS] 2.2.2.2 Interface Release (IFACE_RELEASE)
|
||||
@ -300,121 +264,98 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
status = 0;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == -1)
|
||||
if(status == -1)
|
||||
{
|
||||
DEBUG_WARN("InterfaceId 0x%X FunctionId 0x%X not processed.",
|
||||
InterfaceId, FunctionId);
|
||||
InterfaceId, FunctionId);
|
||||
/* When a request is not implemented we return empty response indicating error */
|
||||
}
|
||||
status = 0;
|
||||
}
|
||||
|
||||
if (status == 0 && !ifman.output_pending)
|
||||
if(status == 0 && !ifman.output_pending)
|
||||
{
|
||||
/* Response packet does not have FunctionId */
|
||||
length = Stream_GetPosition(output);
|
||||
Stream_SetPosition(output, 0);
|
||||
Stream_Write_UINT32(output, ifman.output_interface_id);
|
||||
Stream_Write_UINT32(output, MessageId);
|
||||
|
||||
DEBUG_DVC("response size %d", length);
|
||||
DEBUG_TSMF("response size %d", length);
|
||||
status = callback->channel->Write(callback->channel, length, Stream_Buffer(output), NULL);
|
||||
if (status)
|
||||
if(status)
|
||||
{
|
||||
DEBUG_WARN("response error %d", status);
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Free(output, TRUE);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int tsmf_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
static int tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback)
|
||||
{
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
if (callback->stream_id)
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
DEBUG_TSMF("");
|
||||
if(callback->stream_id)
|
||||
{
|
||||
presentation = tsmf_presentation_find_by_id(callback->presentation_id);
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
stream = tsmf_stream_find_by_id(presentation, callback->stream_id);
|
||||
|
||||
if (stream)
|
||||
if(stream)
|
||||
tsmf_stream_free(stream);
|
||||
}
|
||||
}
|
||||
|
||||
free(pChannelCallback);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
||||
IWTSVirtualChannel* pChannel,
|
||||
BYTE* Data,
|
||||
int* pbAccept,
|
||||
IWTSVirtualChannelCallback** ppCallback)
|
||||
static int tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallback,
|
||||
IWTSVirtualChannel *pChannel,
|
||||
BYTE *Data,
|
||||
int *pbAccept,
|
||||
IWTSVirtualChannelCallback **ppCallback)
|
||||
{
|
||||
TSMF_CHANNEL_CALLBACK* callback;
|
||||
TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*) pListenerCallback;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
callback = (TSMF_CHANNEL_CALLBACK*) malloc(sizeof(TSMF_CHANNEL_CALLBACK));
|
||||
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));
|
||||
|
||||
callback->iface.OnDataReceived = tsmf_on_data_received;
|
||||
callback->iface.OnClose = tsmf_on_close;
|
||||
callback->plugin = listener_callback->plugin;
|
||||
callback->channel_mgr = listener_callback->channel_mgr;
|
||||
callback->channel = pChannel;
|
||||
*ppCallback = (IWTSVirtualChannelCallback*) callback;
|
||||
|
||||
*ppCallback = (IWTSVirtualChannelCallback *) callback;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
||||
static int tsmf_plugin_initialize(IWTSPlugin *pPlugin, IWTSVirtualChannelManager *pChannelMgr)
|
||||
{
|
||||
TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*) malloc(sizeof(TSMF_LISTENER_CALLBACK));
|
||||
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));
|
||||
|
||||
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);
|
||||
(IWTSListenerCallback *) tsmf->listener_callback, NULL);
|
||||
}
|
||||
|
||||
static int tsmf_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
static int tsmf_plugin_terminated(IWTSPlugin *pPlugin)
|
||||
{
|
||||
TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
if (tsmf->listener_callback)
|
||||
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
|
||||
DEBUG_TSMF("");
|
||||
if(tsmf->listener_callback)
|
||||
free(tsmf->listener_callback);
|
||||
free(tsmf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -426,27 +367,21 @@ COMMAND_LINE_ARGUMENT_A tsmf_args[] =
|
||||
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
|
||||
};
|
||||
|
||||
static void tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
|
||||
static void tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args)
|
||||
{
|
||||
int status;
|
||||
DWORD flags;
|
||||
COMMAND_LINE_ARGUMENT_A* arg;
|
||||
TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin;
|
||||
|
||||
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);
|
||||
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char **) args->argv,
|
||||
tsmf_args, flags, tsmf, NULL, NULL);
|
||||
arg = tsmf_args;
|
||||
|
||||
do
|
||||
{
|
||||
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
|
||||
if(!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
|
||||
continue;
|
||||
|
||||
CommandLineSwitchStart(arg)
|
||||
|
||||
CommandLineSwitchCase(arg, "audio")
|
||||
{
|
||||
tsmf->audio_name = _strdup(arg->Value);
|
||||
@ -461,43 +396,35 @@ static void tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
|
||||
}
|
||||
CommandLineSwitchDefault(arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CommandLineSwitchEnd(arg)
|
||||
}
|
||||
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
while((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
#define DVCPluginEntry tsmf_DVCPluginEntry
|
||||
#endif
|
||||
|
||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS *pEntryPoints)
|
||||
{
|
||||
int status = 0;
|
||||
TSMF_PLUGIN* tsmf;
|
||||
|
||||
tsmf = (TSMF_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "tsmf");
|
||||
|
||||
if (tsmf == NULL)
|
||||
TSMF_PLUGIN *tsmf;
|
||||
tsmf = (TSMF_PLUGIN *) pEntryPoints->GetPlugin(pEntryPoints, "tsmf");
|
||||
if(tsmf == NULL)
|
||||
{
|
||||
tsmf = (TSMF_PLUGIN*) malloc(sizeof(TSMF_PLUGIN));
|
||||
tsmf = (TSMF_PLUGIN *) malloc(sizeof(TSMF_PLUGIN));
|
||||
ZeroMemory(tsmf, sizeof(TSMF_PLUGIN));
|
||||
|
||||
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);
|
||||
|
||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin *) tsmf);
|
||||
tsmf_media_init();
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
if(status == 0)
|
||||
{
|
||||
tsmf_process_addin_args((IWTSPlugin*) tsmf, pEntryPoints->GetPluginData(pEntryPoints));
|
||||
tsmf_process_addin_args((IWTSPlugin *) tsmf, pEntryPoints->GetPluginData(pEntryPoints));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,30 +32,31 @@ typedef struct _TSMF_STREAM TSMF_STREAM;
|
||||
|
||||
typedef struct _TSMF_SAMPLE TSMF_SAMPLE;
|
||||
|
||||
TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, IWTSVirtualChannelCallback* pChannelCallback);
|
||||
TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid);
|
||||
void tsmf_presentation_start(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_stop(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_paused(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_restarted(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 newVolume, UINT32 muted);
|
||||
void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation,
|
||||
UINT32 x, UINT32 y, UINT32 width, UINT32 height,
|
||||
int num_rects, RDP_RECT* rects);
|
||||
void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation,
|
||||
const char* name, const char* device);
|
||||
void tsmf_presentation_flush(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_free(TSMF_PRESENTATION* presentation);
|
||||
TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCallback *pChannelCallback);
|
||||
TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid);
|
||||
void tsmf_presentation_start(TSMF_PRESENTATION *presentation);
|
||||
void tsmf_presentation_stop(TSMF_PRESENTATION *presentation);
|
||||
void tsmf_presentation_sync(TSMF_PRESENTATION *presentation);
|
||||
void tsmf_presentation_paused(TSMF_PRESENTATION *presentation);
|
||||
void tsmf_presentation_restarted(TSMF_PRESENTATION *presentation);
|
||||
void tsmf_presentation_volume_changed(TSMF_PRESENTATION *presentation, UINT32 newVolume, UINT32 muted);
|
||||
void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation,
|
||||
UINT32 x, UINT32 y, UINT32 width, UINT32 height,
|
||||
int num_rects, RDP_RECT *rects);
|
||||
void tsmf_presentation_set_audio_device(TSMF_PRESENTATION *presentation,
|
||||
const char *name, const char *device);
|
||||
void tsmf_presentation_flush(TSMF_PRESENTATION *presentation);
|
||||
void tsmf_presentation_free(TSMF_PRESENTATION *presentation);
|
||||
|
||||
TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id);
|
||||
TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stream_id);
|
||||
void tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s);
|
||||
void tsmf_stream_end(TSMF_STREAM* stream);
|
||||
void tsmf_stream_free(TSMF_STREAM* stream);
|
||||
TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id);
|
||||
TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION *presentation, UINT32 stream_id);
|
||||
void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s);
|
||||
void tsmf_stream_end(TSMF_STREAM *stream);
|
||||
void tsmf_stream_free(TSMF_STREAM *stream);
|
||||
|
||||
void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pChannelCallback,
|
||||
UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, UINT32 extensions,
|
||||
UINT32 data_size, BYTE* data);
|
||||
void tsmf_stream_push_sample(TSMF_STREAM *stream, IWTSVirtualChannelCallback *pChannelCallback,
|
||||
UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, UINT32 extensions,
|
||||
UINT32 data_size, BYTE *data);
|
||||
|
||||
void tsmf_media_init(void);
|
||||
|
||||
|
@ -28,10 +28,10 @@
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/utils/debug.h>
|
||||
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
|
||||
#ifdef WITH_DEBUG_TSMF
|
||||
#define DEBUG_TSMF(fmt, ...) DEBUG_CLASS(TSMF, fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#define DEBUG_TSMF(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
typedef struct _TS_AM_MEDIA_TYPE
|
||||
@ -41,7 +41,7 @@ typedef struct _TS_AM_MEDIA_TYPE
|
||||
int FormatType;
|
||||
|
||||
UINT32 Width;
|
||||
UINT32 Height;
|
||||
UINT32 Height;
|
||||
UINT32 BitRate;
|
||||
struct
|
||||
{
|
||||
@ -51,7 +51,7 @@ typedef struct _TS_AM_MEDIA_TYPE
|
||||
UINT32 Channels;
|
||||
UINT32 BitsPerSample;
|
||||
UINT32 BlockAlign;
|
||||
const BYTE* ExtraData;
|
||||
const BYTE *ExtraData;
|
||||
UINT32 ExtraDataSize;
|
||||
} TS_AM_MEDIA_TYPE;
|
||||
|
||||
|
1
client/Android/.gitignore
vendored
1
client/Android/.gitignore
vendored
@ -8,6 +8,7 @@ libs/armeabi*
|
||||
AndroidManifest.xml
|
||||
local.properties
|
||||
!.project
|
||||
appcompat_v7
|
||||
|
||||
FreeRDPCore/project.properties
|
||||
FreeRDPCore/src/com/freerdp/freerdpcore/utils/BuildConfiguration.java
|
||||
|
@ -42,6 +42,11 @@ if(ANDROID_BUILD_JAVA)
|
||||
endif()
|
||||
endif(ANDROID_BUILD_JAVA)
|
||||
|
||||
set(ANDROID_COMMAND "${ANDROID_SDK}/tools/android")
|
||||
if(NOT EXISTS ${ANDROID_COMMAND})
|
||||
message(FATAL_ERROR "android not found but required to build android java")
|
||||
endif()
|
||||
|
||||
if(ANDROID_BUILD_JAVA_DEBUG)
|
||||
set(ANDROID_BUILD_TYPE "debug")
|
||||
else()
|
||||
@ -56,5 +61,11 @@ else()
|
||||
set(NDK_DEBUG "0")
|
||||
endif()
|
||||
|
||||
set(APPCOMPAT_DIR "${CMAKE_CURRENT_BINARY_DIR}/appcompat_v7")
|
||||
add_custom_target(copy_appcompat ALL
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${ANDROID_SDK}/extras/android/support/v7/appcompat ${APPCOMPAT_DIR}
|
||||
COMMAND ${ANDROID_COMMAND} update lib-project -p ${APPCOMPAT_DIR}
|
||||
)
|
||||
|
||||
add_subdirectory(FreeRDPCore)
|
||||
add_subdirectory(aFreeRDP)
|
||||
|
@ -65,7 +65,7 @@
|
||||
android:windowSoftInputMode="stateHidden">
|
||||
</activity>
|
||||
<activity android:name=".presentation.SessionActivity"
|
||||
android:theme="@android:style/Theme.Black.NoTitleBar"
|
||||
android:theme="@style/Theme.AppCompat"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
</activity>
|
||||
|
@ -203,8 +203,6 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
result = init_callback_environment(vm);
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
freerdp_channels_global_init();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
3
client/Android/FreeRDPCore/lint.xml
Normal file
3
client/Android/FreeRDPCore/lint.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
</lint>
|
@ -13,3 +13,4 @@
|
||||
# Project target.
|
||||
target=android-@ANDROID_APP_TARGET_SDK@
|
||||
android.library=true
|
||||
android.library.reference.1=../appcompat_v7
|
||||
|
@ -18,7 +18,6 @@
|
||||
android:paddingRight="6dip"
|
||||
android:paddingTop="7dip"
|
||||
android:paddingBottom="16dip"
|
||||
android:background="@drawable/search_plate"
|
||||
android:gravity="center_vertical"
|
||||
android:focusable="true"
|
||||
android:descendantFocusability="afterDescendants">
|
||||
@ -36,8 +35,6 @@
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:inputType="text"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textColorHint="?android:attr/textColorHint"
|
||||
android:drawableLeft="@drawable/icon_edittext_search"
|
||||
android:drawableRight="@drawable/icon_edittext_clear"
|
||||
/>
|
||||
|
@ -4,14 +4,17 @@
|
||||
|
||||
<item android:id="@+id/bookmark_connect"
|
||||
android:title="@string/menu_connect"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
|
||||
<item android:id="@+id/bookmark_edit"
|
||||
android:title="@string/menu_edit"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
|
||||
<item android:id="@+id/bookmark_delete"
|
||||
android:title="@string/menu_delete"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
|
||||
</menu>
|
||||
|
@ -4,21 +4,21 @@
|
||||
<item android:id="@+id/newBookmark"
|
||||
android:icon="@drawable/icon_menu_add"
|
||||
android:title="@string/menu_new_bookmark"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/appSettings"
|
||||
android:icon="@drawable/icon_menu_settings"
|
||||
android:title="@string/menu_app_settings"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/help"
|
||||
android:icon="@drawable/icon_menu_help"
|
||||
android:title="@string/menu_help"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/about"
|
||||
android:icon="@drawable/icon_menu_about"
|
||||
android:title="@string/menu_about"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/exit"
|
||||
android:icon="@drawable/icon_menu_exit"
|
||||
android:title="@string/menu_exit"
|
||||
/>
|
||||
</menu>
|
||||
|
@ -5,22 +5,27 @@
|
||||
<item android:id="@+id/session_touch_pointer"
|
||||
android:title="@string/pointer"
|
||||
android:icon="@drawable/icon_zoom_in"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
-->
|
||||
<item android:id="@+id/session_touch_pointer"
|
||||
android:title="@string/menu_touch_pointer"
|
||||
android:icon="@drawable/icon_menu_touch_pointer"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/session_sys_keyboard"
|
||||
android:title="@string/menu_sys_keyboard"
|
||||
android:icon="@drawable/icon_menu_sys_keyboard"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/session_ext_keyboard"
|
||||
android:title="@string/menu_ext_keyboard"
|
||||
android:icon="@drawable/icon_menu_ext_keyboard"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
<item android:id="@+id/session_disconnect"
|
||||
android:title="@string/menu_disconnect"
|
||||
android:icon="@drawable/icon_menu_disconnect"
|
||||
android:showAsAction="ifRoom"
|
||||
/>
|
||||
</menu>
|
||||
|
@ -23,7 +23,7 @@
|
||||
<string name="menu_ext_keyboard">Funcion teclado</string>
|
||||
<string name="menu_touch_pointer">Puntero Tactil</string>
|
||||
<string name="menu_home">Inicio</string>
|
||||
<string name="menu_disconnect">desconectart</string>
|
||||
<string name="menu_disconnect">Desconectart</string>
|
||||
<!-- List section headers -->
|
||||
<string name="section_bookmarks">Conexión Manual</string>
|
||||
<string name="section_active_sessions">Sesiones Activas</string>
|
||||
@ -197,4 +197,6 @@
|
||||
<string name="dlg_msg_exit">Esta seguro que desea salir del programa?</string>
|
||||
<string name="dlg_title_clear_cert_cache">Borrar Certificados?</string>
|
||||
<string name="dlg_msg_clear_cert_cache">Esta seguro que desea borrar todos los certificados?</string>
|
||||
<string name="debug_level">Debug Level</string>
|
||||
<string name="settings_debug">Debug Settings</string>
|
||||
</resources>
|
||||
|
@ -196,4 +196,6 @@
|
||||
<string name="dlg_msg_exit">"Êtes-vous sûr de vouloir quitter l'application?"</string>
|
||||
<string name="dlg_title_clear_cert_cache">"Êtes-vous sûrs de vouloir supprimer les certificats?"</string>
|
||||
<string name="dlg_msg_clear_cert_cache">"Êtes-vous sûr de vouloir supprimer tous les certificats mis en cache?"</string>
|
||||
<string name="debug_level">Debug Level</string>
|
||||
<string name="settings_debug">Debug Settings</string>
|
||||
</resources>
|
||||
|
@ -197,4 +197,6 @@
|
||||
<string name="dlg_msg_exit">Weet u zeker dat u de applicatie wilt sluiten?</string>
|
||||
<string name="dlg_title_clear_cert_cache">Verwijder certificaten?</string>
|
||||
<string name="dlg_msg_clear_cert_cache">Weet u zeker dat u al uw cache certificaten wilt verwijderen?</string>
|
||||
<string name="debug_level">Debug Level</string>
|
||||
<string name="settings_debug">Debug Settings</string>
|
||||
</resources>
|
||||
|
@ -23,7 +23,7 @@
|
||||
<string name="menu_ext_keyboard">Function Keys</string>
|
||||
<string name="menu_touch_pointer">Touch Pointer</string>
|
||||
<string name="menu_home">home</string>
|
||||
<string name="menu_disconnect">disconnect</string>
|
||||
<string name="menu_disconnect">Disconnect</string>
|
||||
<!-- List section headers -->
|
||||
<string name="section_bookmarks">Manual Connections</string>
|
||||
<string name="section_active_sessions">Active Sessions</string>
|
||||
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<resources>
|
||||
<style name="Theme.Settings" parent="android:Theme.Light">
|
||||
<style name="Theme.Settings" parent="@style/Theme.AppCompat">
|
||||
<item name="android:listSeparatorTextViewStyle">@style/SettingsCategory</item>
|
||||
</style>
|
||||
<style name="Theme.Main" parent="android:Theme.Light">
|
||||
<style name="Theme.Main" parent="@style/Theme.AppCompat">
|
||||
</style>
|
||||
<style name="SettingsCategory">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
|
@ -363,10 +363,6 @@ public class HomeActivity extends Activity
|
||||
Intent helpIntent = new Intent(this, HelpActivity.class);
|
||||
startActivity(helpIntent);
|
||||
}
|
||||
else if (itemId == R.id.exit)
|
||||
{
|
||||
finish();
|
||||
}
|
||||
else if (itemId == R.id.about)
|
||||
{
|
||||
Intent aboutIntent = new Intent(this, AboutActivity.class);
|
||||
|
File diff suppressed because it is too large
Load Diff
3
client/Android/aFreeRDP/lint.xml
Normal file
3
client/Android/aFreeRDP/lint.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
</lint>
|
20
client/Android/aFreeRDP/proguard-project.txt
Normal file
20
client/Android/aFreeRDP/proguard-project.txt
Normal file
@ -0,0 +1,20 @@
|
||||
# To enable ProGuard in your project, edit project.properties
|
||||
# to define the proguard.config property as described in that file.
|
||||
#
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in ${sdk.dir}/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the ProGuard
|
||||
# include property in project.properties.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
@ -441,8 +441,6 @@ int main(int argc, char* argv[])
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
freerdp_channels_global_init();
|
||||
|
||||
g_sem = CreateSemaphore(NULL, 0, 1, NULL);
|
||||
|
||||
instance = freerdp_new();
|
||||
@ -484,7 +482,5 @@ int main(int argc, char* argv[])
|
||||
WaitForSingleObject(g_sem, INFINITE);
|
||||
}
|
||||
|
||||
freerdp_channels_global_uninit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -760,8 +760,6 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type)
|
||||
return;
|
||||
|
||||
gdi_free(context->instance);
|
||||
|
||||
freerdp_channels_global_uninit();
|
||||
|
||||
if (pixel_data)
|
||||
free(pixel_data);
|
||||
|
@ -33,12 +33,11 @@
|
||||
void mfreerdp_client_global_init()
|
||||
{
|
||||
freerdp_handle_signals();
|
||||
freerdp_channels_global_init();
|
||||
}
|
||||
|
||||
void mfreerdp_client_global_uninit()
|
||||
{
|
||||
freerdp_channels_global_uninit();
|
||||
|
||||
}
|
||||
|
||||
int mfreerdp_client_start(rdpContext* context)
|
||||
|
@ -305,8 +305,6 @@ int main(int argc, char* argv[])
|
||||
rdpChannels* channels;
|
||||
struct thread_data* data;
|
||||
|
||||
freerdp_channels_global_init();
|
||||
|
||||
g_sem = CreateSemaphore(NULL, 0, 1, NULL);
|
||||
|
||||
instance = freerdp_new();
|
||||
@ -341,7 +339,5 @@ int main(int argc, char* argv[])
|
||||
WaitForSingleObject(g_sem, INFINITE);
|
||||
}
|
||||
|
||||
freerdp_channels_global_uninit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/event.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#include <freerdp/client/file.h>
|
||||
#include <freerdp/client/cmdline.h>
|
||||
|
@ -43,9 +43,7 @@
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/event.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
//#include <freerdp/client/file.h>
|
||||
#include <freerdp/client/cmdline.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
#include <freerdp/channels/channels.h>
|
||||
@ -1171,8 +1169,6 @@ void wfreerdp_client_global_init(void)
|
||||
wf_create_console();
|
||||
#endif
|
||||
|
||||
freerdp_channels_global_init();
|
||||
|
||||
freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@ include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
xf_gdi.c
|
||||
xf_gdi.h
|
||||
xf_gfx.c
|
||||
xf_gfx.h
|
||||
xf_rail.c
|
||||
xf_rail.h
|
||||
xf_tsmf.c
|
||||
|
@ -9,33 +9,28 @@
|
||||
* the argument struct. */
|
||||
#include "../common/cmdline.c"
|
||||
|
||||
LPSTR tmp = NULL;
|
||||
|
||||
LPSTR tr_esc_str(LPCSTR arg)
|
||||
{
|
||||
LPSTR tmp = NULL;
|
||||
size_t cs = 0, x, ds;
|
||||
size_t s;
|
||||
|
||||
if( NULL == arg )
|
||||
if(NULL == arg)
|
||||
return NULL;
|
||||
|
||||
s = strlen(arg);
|
||||
|
||||
/* Find trailing whitespaces */
|
||||
while( (s > 0) && isspace(arg[s-1]))
|
||||
while((s > 0) && isspace(arg[s-1]))
|
||||
s--;
|
||||
|
||||
/* Prepare a initial buffer with the size of the result string. */
|
||||
if (s)
|
||||
tmp = (LPSTR)malloc(s * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
ds = s + 1;
|
||||
if(s)
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not allocate string buffer.");
|
||||
exit(-2);
|
||||
}
|
||||
|
||||
/* Copy character for character and check, if it is necessary to escape. */
|
||||
ds = s + 1;
|
||||
memset(tmp, 0, ds * sizeof(CHAR));
|
||||
for(x=0; x<s; x++)
|
||||
{
|
||||
switch(arg[x])
|
||||
@ -43,7 +38,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '<':
|
||||
ds += 3;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-3);
|
||||
@ -56,7 +51,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '>':
|
||||
ds += 3;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-4);
|
||||
@ -69,7 +64,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '\'':
|
||||
ds += 5;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-5);
|
||||
@ -84,7 +79,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '"':
|
||||
ds += 5;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-6);
|
||||
@ -99,7 +94,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '&':
|
||||
ds += 4;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-7);
|
||||
@ -114,11 +109,9 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
tmp[cs++] = arg[x];
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assure, the string is '\0' terminated. */
|
||||
tmp[ds-1] = '\0';
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@ -128,51 +121,46 @@ int main(int argc, char *argv[])
|
||||
size_t x;
|
||||
const char *fname = "xfreerdp-argument.1.xml";
|
||||
FILE *fp = NULL;
|
||||
|
||||
/* Open output file for writing, truncate if existing. */
|
||||
fp = fopen(fname, "w");
|
||||
if( NULL == fp )
|
||||
if(NULL == fp)
|
||||
{
|
||||
fprintf(stderr, "Could not open '%s' for writing.", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The tag used as header in the manpage */
|
||||
fprintf(fp, "<refsect1>\n");
|
||||
fprintf(fp, "\t<title>Options</title>\n");
|
||||
fprintf(fp, "\t\t<variablelist>\n");
|
||||
|
||||
/* Iterate over argument struct and write data to docbook 4.5
|
||||
/* Iterate over argument struct and write data to docbook 4.5
|
||||
* compatible XML */
|
||||
if( elements < 2 )
|
||||
if(elements < 2)
|
||||
{
|
||||
fprintf(stderr, "The argument array 'args' is empty, writing an empty file.");
|
||||
elements = 1;
|
||||
}
|
||||
|
||||
for(x=0; x<elements - 1; x++)
|
||||
{
|
||||
const COMMAND_LINE_ARGUMENT_A *arg = &args[x];
|
||||
|
||||
const char *name = tr_esc_str((LPSTR) arg->Name);
|
||||
const char *format = tr_esc_str(arg->Format);
|
||||
const char *text = tr_esc_str((LPSTR) arg->Text);
|
||||
fprintf(fp, "\t\t\t<varlistentry>\n");
|
||||
if ( COMMAND_LINE_VALUE_REQUIRED == arg->Flags)
|
||||
fprintf(fp, "\t\t\t\t<term><option>/%s</option> <replaceable>%s</replaceable></term>\n", tr_esc_str((LPSTR) arg->Name), tr_esc_str(arg->Format) );
|
||||
if(COMMAND_LINE_VALUE_REQUIRED == arg->Flags)
|
||||
fprintf(fp, "\t\t\t\t<term><option>/%s</option> <replaceable>%s</replaceable></term>\n", name, format);
|
||||
else
|
||||
fprintf(fp, "\t\t\t\t<term><option>/%s</option></term>\n", tr_esc_str((LPSTR) arg->Name));
|
||||
fprintf(fp, "\t\t\t\t<term><option>/%s</option></term>\n", name);
|
||||
fprintf(fp, "\t\t\t\t<listitem>\n");
|
||||
fprintf(fp, "\t\t\t\t\t<para>%s</para>\n", tr_esc_str((LPSTR) arg->Text));
|
||||
|
||||
fprintf(fp, "\t\t\t\t\t<para>%s</para>\n", format);
|
||||
fprintf(fp, "\t\t\t\t</listitem>\n");
|
||||
fprintf(fp, "\t\t\t</varlistentry>\n");
|
||||
free((void*) name);
|
||||
free((void*) format);
|
||||
free((void*) text);
|
||||
}
|
||||
|
||||
fprintf(fp, "\t\t</variablelist>\n");
|
||||
fprintf(fp, "\t</refsect1>\n");
|
||||
fclose(fp);
|
||||
|
||||
if(NULL != tmp)
|
||||
free(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
#include "xf_gfx.h"
|
||||
|
||||
void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
@ -34,9 +36,22 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEven
|
||||
{
|
||||
xfc->rdpei = (RdpeiClientContext*) e->pInterface;
|
||||
}
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_graphics_pipeline_init(xfc, (RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
}
|
||||
|
||||
void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
|
||||
if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xfc->rdpei = NULL;
|
||||
}
|
||||
else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
|
||||
{
|
||||
xf_graphics_pipeline_uninit(xfc, (RdpgfxClientContext*) e->pInterface);
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/client/channels.h>
|
||||
#include <freerdp/client/rdpei.h>
|
||||
#include <freerdp/client/rdpgfx.h>
|
||||
|
||||
int xf_on_channel_connected(freerdp* instance, const char* name, void* pInterface);
|
||||
int xf_on_channel_disconnected(freerdp* instance, const char* name, void* pInterface);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,7 @@
|
||||
#include "xf_window.h"
|
||||
#include "xf_cliprdr.h"
|
||||
#include "xf_input.h"
|
||||
#include "xf_gfx.h"
|
||||
|
||||
#include "xf_event.h"
|
||||
#include "xf_input.h"
|
||||
@ -189,7 +190,13 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app)
|
||||
y = event->xexpose.y;
|
||||
w = event->xexpose.width;
|
||||
h = event->xexpose.height;
|
||||
|
||||
|
||||
if (xfc->gfx)
|
||||
{
|
||||
xf_OutputExpose(xfc, x, y, w, h);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!app)
|
||||
{
|
||||
if ((xfc->settings->ScalingFactor != 1.0) || (xfc->offset_x) || (xfc->offset_y))
|
||||
@ -199,9 +206,7 @@ static BOOL xf_event_Expose(xfContext* xfc, XEvent* event, BOOL app)
|
||||
}
|
||||
else
|
||||
{
|
||||
XCopyArea(xfc->display, xfc->primary,
|
||||
xfc->window->handle, xfc->gc, x, y, w,
|
||||
h, x, y);
|
||||
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, x, y, w, h, x, y);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -990,14 +990,12 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits
|
||||
XImage* image;
|
||||
RFX_MESSAGE* message;
|
||||
xfContext* xfc = (xfContext*) context;
|
||||
RFX_CONTEXT* rfx_context = (RFX_CONTEXT*) xfc->rfx_context;
|
||||
NSC_CONTEXT* nsc_context = (NSC_CONTEXT*) xfc->nsc_context;
|
||||
|
||||
xf_lock_x11(xfc, FALSE);
|
||||
|
||||
if (surface_bits_command->codecID == RDP_CODEC_ID_REMOTEFX)
|
||||
{
|
||||
message = rfx_process_message(rfx_context,
|
||||
message = rfx_process_message(xfc->rfx,
|
||||
surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength);
|
||||
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
@ -1034,11 +1032,11 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits
|
||||
}
|
||||
|
||||
XSetClipMask(xfc->display, xfc->gc, None);
|
||||
rfx_message_free(rfx_context, message);
|
||||
rfx_message_free(xfc->rfx, message);
|
||||
}
|
||||
else if (surface_bits_command->codecID == RDP_CODEC_ID_NSCODEC)
|
||||
{
|
||||
nsc_process_message(nsc_context, surface_bits_command->bpp, surface_bits_command->width, surface_bits_command->height,
|
||||
nsc_process_message(xfc->nsc, surface_bits_command->bpp, surface_bits_command->width, surface_bits_command->height,
|
||||
surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength);
|
||||
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
@ -1047,7 +1045,7 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits
|
||||
xfc->bmp_codec_nsc = (BYTE*) realloc(xfc->bmp_codec_nsc,
|
||||
surface_bits_command->width * surface_bits_command->height * 4);
|
||||
|
||||
freerdp_image_flip(nsc_context->BitmapData, xfc->bmp_codec_nsc,
|
||||
freerdp_image_flip(xfc->nsc->BitmapData, xfc->bmp_codec_nsc,
|
||||
surface_bits_command->width, surface_bits_command->height, 32);
|
||||
|
||||
image = XCreateImage(xfc->display, xfc->visual, 24, ZPixmap, 0,
|
||||
@ -1060,13 +1058,14 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits
|
||||
free(xfc->bmp_codec_nsc);
|
||||
xfc->bmp_codec_nsc = NULL;
|
||||
|
||||
if (xfc->remote_app != TRUE)
|
||||
if (!xfc->remote_app)
|
||||
{
|
||||
XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc,
|
||||
surface_bits_command->destLeft, surface_bits_command->destTop,
|
||||
surface_bits_command->width, surface_bits_command->height,
|
||||
surface_bits_command->destLeft, surface_bits_command->destTop);
|
||||
}
|
||||
|
||||
xf_gdi_surface_update_frame(xfc,
|
||||
surface_bits_command->destLeft, surface_bits_command->destTop,
|
||||
surface_bits_command->width, surface_bits_command->height);
|
||||
|
672
client/X11/xf_gfx.c
Normal file
672
client/X11/xf_gfx.c
Normal file
@ -0,0 +1,672 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Graphics Pipeline
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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
|
||||
|
||||
#include "xf_gfx.h"
|
||||
|
||||
int xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
printf("xf_ResetGraphics: width: %d height: %d\n",
|
||||
resetGraphics->width, resetGraphics->height);
|
||||
|
||||
if (xfc->rfx)
|
||||
{
|
||||
rfx_context_free(xfc->rfx);
|
||||
xfc->rfx = NULL;
|
||||
}
|
||||
|
||||
xfc->rfx = rfx_context_new(FALSE);
|
||||
|
||||
xfc->rfx->width = resetGraphics->width;
|
||||
xfc->rfx->height = resetGraphics->height;
|
||||
rfx_context_set_pixel_format(xfc->rfx, RDP_PIXEL_FORMAT_B8G8R8A8);
|
||||
|
||||
if (xfc->nsc)
|
||||
{
|
||||
nsc_context_free(xfc->nsc);
|
||||
xfc->nsc = NULL;
|
||||
}
|
||||
|
||||
xfc->nsc = nsc_context_new();
|
||||
|
||||
xfc->nsc->width = resetGraphics->width;
|
||||
xfc->nsc->height = resetGraphics->height;
|
||||
nsc_context_set_pixel_format(xfc->nsc, RDP_PIXEL_FORMAT_B8G8R8A8);
|
||||
|
||||
xfc->clear = clear_context_new(FALSE);
|
||||
|
||||
region16_init(&(xfc->invalidRegion));
|
||||
|
||||
xfc->graphicsReset = TRUE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_OutputUpdate(xfContext* xfc)
|
||||
{
|
||||
UINT16 width, height;
|
||||
xfGfxSurface* surface;
|
||||
RECTANGLE_16 surfaceRect;
|
||||
const RECTANGLE_16* extents;
|
||||
|
||||
if (!xfc->graphicsReset)
|
||||
return 1;
|
||||
|
||||
surface = (xfGfxSurface*) xfc->gfx->GetSurfaceData(xfc->gfx, xfc->outputSurfaceId);
|
||||
|
||||
if (!surface)
|
||||
return -1;
|
||||
|
||||
surfaceRect.left = 0;
|
||||
surfaceRect.top = 0;
|
||||
surfaceRect.right = xfc->width;
|
||||
surfaceRect.bottom = xfc->height;
|
||||
|
||||
region16_intersect_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &surfaceRect);
|
||||
|
||||
XSetClipMask(xfc->display, xfc->gc, None);
|
||||
XSetFunction(xfc->display, xfc->gc, GXcopy);
|
||||
XSetFillStyle(xfc->display, xfc->gc, FillSolid);
|
||||
|
||||
if (!region16_is_empty(&(xfc->invalidRegion)))
|
||||
{
|
||||
extents = region16_extents(&(xfc->invalidRegion));
|
||||
|
||||
width = extents->right - extents->left;
|
||||
height = extents->bottom - extents->top;
|
||||
|
||||
if (width > xfc->width)
|
||||
width = xfc->width;
|
||||
|
||||
if (height > xfc->height)
|
||||
height = xfc->height;
|
||||
|
||||
XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image,
|
||||
extents->left, extents->top,
|
||||
extents->left, extents->top, width, height);
|
||||
}
|
||||
|
||||
region16_clear(&(xfc->invalidRegion));
|
||||
|
||||
XSetClipMask(xfc->display, xfc->gc, None);
|
||||
XSync(xfc->display, True);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_OutputExpose(xfContext* xfc, int x, int y, int width, int height)
|
||||
{
|
||||
RECTANGLE_16 invalidRect;
|
||||
|
||||
invalidRect.left = x;
|
||||
invalidRect.top = y;
|
||||
invalidRect.right = x + width;
|
||||
invalidRect.bottom = y + height;
|
||||
|
||||
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
|
||||
|
||||
xf_OutputUpdate(xfc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFrame)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
xfc->inGfxFrame = TRUE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
xf_OutputUpdate(xfc);
|
||||
|
||||
xfc->inGfxFrame = FALSE;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
xfGfxSurface* surface;
|
||||
RECTANGLE_16 invalidRect;
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId);
|
||||
|
||||
if (!surface)
|
||||
return -1;
|
||||
|
||||
freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top,
|
||||
cmd->width, cmd->height, cmd->data, PIXEL_FORMAT_XRGB32, cmd->width * 4, 0, 0);
|
||||
|
||||
invalidRect.left = cmd->left;
|
||||
invalidRect.top = cmd->top;
|
||||
invalidRect.right = cmd->right;
|
||||
invalidRect.bottom = cmd->bottom;
|
||||
|
||||
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
|
||||
|
||||
if (!xfc->inGfxFrame)
|
||||
xf_OutputUpdate(xfc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int j;
|
||||
UINT16 i;
|
||||
RFX_RECT* rect;
|
||||
RFX_TILE* tile;
|
||||
int nXDst, nYDst;
|
||||
int nWidth, nHeight;
|
||||
int nbUpdateRects;
|
||||
RFX_MESSAGE* message;
|
||||
xfGfxSurface* surface;
|
||||
REGION16 updateRegion;
|
||||
RECTANGLE_16 updateRect;
|
||||
RECTANGLE_16* updateRects;
|
||||
REGION16 clippingRects;
|
||||
RECTANGLE_16 clippingRect;
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId);
|
||||
|
||||
if (!surface)
|
||||
return -1;
|
||||
|
||||
message = rfx_process_message(xfc->rfx, cmd->data, cmd->length);
|
||||
|
||||
if (!message)
|
||||
return -1;
|
||||
|
||||
region16_init(&clippingRects);
|
||||
|
||||
for (i = 0; i < message->numRects; i++)
|
||||
{
|
||||
rect = &(message->rects[i]);
|
||||
|
||||
clippingRect.left = cmd->left + rect->x;
|
||||
clippingRect.top = cmd->top + rect->y;
|
||||
clippingRect.right = clippingRect.left + rect->width;
|
||||
clippingRect.bottom = clippingRect.top + rect->height;
|
||||
|
||||
region16_union_rect(&clippingRects, &clippingRects, &clippingRect);
|
||||
}
|
||||
|
||||
for (i = 0; i < message->numTiles; i++)
|
||||
{
|
||||
tile = message->tiles[i];
|
||||
|
||||
updateRect.left = cmd->left + tile->x;
|
||||
updateRect.top = cmd->top + tile->y;
|
||||
updateRect.right = updateRect.left + 64;
|
||||
updateRect.bottom = updateRect.top + 64;
|
||||
|
||||
region16_init(&updateRegion);
|
||||
region16_intersect_rect(&updateRegion, &clippingRects, &updateRect);
|
||||
updateRects = (RECTANGLE_16*) region16_rects(&updateRegion, &nbUpdateRects);
|
||||
|
||||
for (j = 0; j < nbUpdateRects; j++)
|
||||
{
|
||||
nXDst = updateRects[j].left;
|
||||
nYDst = updateRects[j].top;
|
||||
nWidth = updateRects[j].right - updateRects[j].left;
|
||||
nHeight = updateRects[j].bottom - updateRects[j].top;
|
||||
|
||||
freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
|
||||
nXDst, nYDst, nWidth, nHeight,
|
||||
tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, 0, 0);
|
||||
|
||||
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &updateRects[j]);
|
||||
}
|
||||
|
||||
region16_uninit(&updateRegion);
|
||||
}
|
||||
|
||||
rfx_message_free(xfc->rfx, message);
|
||||
|
||||
if (!xfc->inGfxFrame)
|
||||
xf_OutputUpdate(xfc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status;
|
||||
UINT32 DstSize = 0;
|
||||
BYTE* pDstData = NULL;
|
||||
xfGfxSurface* surface;
|
||||
RECTANGLE_16 invalidRect;
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId);
|
||||
|
||||
if (!surface)
|
||||
return -1;
|
||||
|
||||
status = clear_decompress(xfc->clear, cmd->data, cmd->length, &pDstData, &DstSize);
|
||||
|
||||
printf("xf_SurfaceCommand_ClearCodec: status: %d\n", status);
|
||||
|
||||
/* fill with pink for now to distinguish from the rest */
|
||||
|
||||
freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
|
||||
cmd->left, cmd->top, cmd->width, cmd->height, 0xFF69B4);
|
||||
|
||||
invalidRect.left = cmd->left;
|
||||
invalidRect.top = cmd->top;
|
||||
invalidRect.right = cmd->right;
|
||||
invalidRect.bottom = cmd->bottom;
|
||||
|
||||
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
|
||||
|
||||
if (!xfc->inGfxFrame)
|
||||
xf_OutputUpdate(xfc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status;
|
||||
BYTE* DstData = NULL;
|
||||
xfGfxSurface* surface;
|
||||
RECTANGLE_16 invalidRect;
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId);
|
||||
|
||||
if (!surface)
|
||||
return -1;
|
||||
|
||||
DstData = surface->data;
|
||||
|
||||
status = planar_decompress(NULL, cmd->data, cmd->length, &DstData,
|
||||
PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height);
|
||||
|
||||
invalidRect.left = cmd->left;
|
||||
invalidRect.top = cmd->top;
|
||||
invalidRect.right = cmd->right;
|
||||
invalidRect.bottom = cmd->bottom;
|
||||
|
||||
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
|
||||
|
||||
if (!xfc->inGfxFrame)
|
||||
xf_OutputUpdate(xfc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd)
|
||||
{
|
||||
int status = 1;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
switch (cmd->codecId)
|
||||
{
|
||||
case RDPGFX_CODECID_UNCOMPRESSED:
|
||||
status = xf_SurfaceCommand_Uncompressed(xfc, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_CAVIDEO:
|
||||
status = xf_SurfaceCommand_RemoteFX(xfc, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_CLEARCODEC:
|
||||
status = xf_SurfaceCommand_ClearCodec(xfc, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_PLANAR:
|
||||
status = xf_SurfaceCommand_Planar(xfc, context, cmd);
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_H264:
|
||||
printf("xf_SurfaceCommand_H264\n");
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_ALPHA:
|
||||
printf("xf_SurfaceCommand_Alpha\n");
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_CAPROGRESSIVE:
|
||||
printf("xf_SurfaceCommand_Progressive\n");
|
||||
break;
|
||||
|
||||
case RDPGFX_CODECID_CAPROGRESSIVE_V2:
|
||||
printf("xf_SurfaceCommand_ProgressiveV2\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_DeleteEncodingContext(RdpgfxClientContext* context, RDPGFX_DELETE_ENCODING_CONTEXT_PDU* deleteEncodingContext)
|
||||
{
|
||||
printf("xf_DeleteEncodingContext\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* createSurface)
|
||||
{
|
||||
xfGfxSurface* surface;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
printf("xf_CreateSurface: surfaceId: %d width: %d height: %d format: 0x%02X\n",
|
||||
createSurface->surfaceId, createSurface->width, createSurface->height, createSurface->pixelFormat);
|
||||
|
||||
surface = (xfGfxSurface*) calloc(1, sizeof(xfGfxSurface));
|
||||
|
||||
if (!surface)
|
||||
return -1;
|
||||
|
||||
surface->surfaceId = createSurface->surfaceId;
|
||||
surface->width = (UINT32) createSurface->width;
|
||||
surface->height = (UINT32) createSurface->height;
|
||||
surface->alpha = (createSurface->pixelFormat == PIXEL_FORMAT_ARGB_8888) ? TRUE : FALSE;
|
||||
|
||||
surface->scanline = (surface->width + (surface->width % 4)) * 4;
|
||||
surface->data = (BYTE*) calloc(1, surface->scanline * surface->height);
|
||||
|
||||
if (!surface->data)
|
||||
return -1;
|
||||
|
||||
surface->image = XCreateImage(xfc->display, xfc->visual, 24, ZPixmap, 0,
|
||||
(char*) surface->data, surface->width, surface->height, 32, surface->scanline);
|
||||
|
||||
context->SetSurfaceData(context, surface->surfaceId, (void*) surface);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* deleteSurface)
|
||||
{
|
||||
xfGfxSurface* surface = NULL;
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, deleteSurface->surfaceId);
|
||||
|
||||
printf("xf_DeleteSurface: surfaceId: %d\n", deleteSurface->surfaceId);
|
||||
|
||||
if (surface)
|
||||
{
|
||||
XFree(surface->image);
|
||||
free(surface->data);
|
||||
free(surface);
|
||||
}
|
||||
|
||||
context->SetSurfaceData(context, deleteSurface->surfaceId, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill)
|
||||
{
|
||||
UINT16 index;
|
||||
UINT32 color;
|
||||
BYTE a, r, g, b;
|
||||
int nWidth, nHeight;
|
||||
RDPGFX_RECT16* rect;
|
||||
xfGfxSurface* surface;
|
||||
RECTANGLE_16 invalidRect;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, solidFill->surfaceId);
|
||||
|
||||
printf("xf_SolidFill\n");
|
||||
|
||||
if (!surface)
|
||||
return -1;
|
||||
|
||||
b = solidFill->fillPixel.B;
|
||||
g = solidFill->fillPixel.G;
|
||||
r = solidFill->fillPixel.R;
|
||||
a = solidFill->fillPixel.XA;
|
||||
|
||||
color = ARGB32(a, r, g, b);
|
||||
|
||||
for (index = 0; index < solidFill->fillRectCount; index++)
|
||||
{
|
||||
rect = &(solidFill->fillRects[index]);
|
||||
|
||||
nWidth = rect->right - rect->left;
|
||||
nHeight = rect->bottom - rect->top;
|
||||
|
||||
invalidRect.left = rect->left;
|
||||
invalidRect.top = rect->top;
|
||||
invalidRect.right = rect->right;
|
||||
invalidRect.bottom = rect->bottom;
|
||||
|
||||
freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
|
||||
rect->left, rect->top, nWidth, nHeight, color);
|
||||
|
||||
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
|
||||
}
|
||||
|
||||
if (!xfc->inGfxFrame)
|
||||
xf_OutputUpdate(xfc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_PDU* surfaceToSurface)
|
||||
{
|
||||
UINT16 index;
|
||||
int nWidth, nHeight;
|
||||
RDPGFX_RECT16* rectSrc;
|
||||
RDPGFX_POINT16* destPt;
|
||||
RECTANGLE_16 invalidRect;
|
||||
xfGfxSurface* surfaceSrc;
|
||||
xfGfxSurface* surfaceDst;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
rectSrc = &(surfaceToSurface->rectSrc);
|
||||
destPt = &surfaceToSurface->destPts[0];
|
||||
|
||||
surfaceSrc = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToSurface->surfaceIdSrc);
|
||||
|
||||
if (surfaceToSurface->surfaceIdSrc != surfaceToSurface->surfaceIdDest)
|
||||
surfaceDst = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToSurface->surfaceIdDest);
|
||||
else
|
||||
surfaceDst = surfaceSrc;
|
||||
|
||||
if (!surfaceSrc || !surfaceDst)
|
||||
return -1;
|
||||
|
||||
nWidth = rectSrc->right - rectSrc->left + 1;
|
||||
nHeight = rectSrc->bottom - rectSrc->top + 1;
|
||||
|
||||
for (index = 0; index < surfaceToSurface->destPtsCount; index++)
|
||||
{
|
||||
destPt = &surfaceToSurface->destPts[index];
|
||||
|
||||
freerdp_image_copy(surfaceDst->data, PIXEL_FORMAT_XRGB32, surfaceDst->scanline,
|
||||
destPt->x, destPt->y, nWidth, nHeight, surfaceSrc->data, PIXEL_FORMAT_XRGB32,
|
||||
surfaceSrc->scanline, rectSrc->left, rectSrc->top);
|
||||
|
||||
invalidRect.left = destPt->x;
|
||||
invalidRect.top = destPt->y;
|
||||
invalidRect.right = destPt->x + rectSrc->right;
|
||||
invalidRect.bottom = destPt->y + rectSrc->bottom;
|
||||
|
||||
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
|
||||
}
|
||||
|
||||
if (!xfc->inGfxFrame)
|
||||
xf_OutputUpdate(xfc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surfaceToCache)
|
||||
{
|
||||
RDPGFX_RECT16* rect;
|
||||
xfGfxSurface* surface;
|
||||
xfGfxCacheEntry* cacheEntry;
|
||||
|
||||
rect = &(surfaceToCache->rectSrc);
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToCache->surfaceId);
|
||||
|
||||
//printf("xf_SurfaceToCache: cacheKey: 0x%016X cacheSlot: %ld\n",
|
||||
// surfaceToCache->cacheKey, surfaceToCache->cacheSlot);
|
||||
|
||||
if (!surface)
|
||||
return -1;
|
||||
|
||||
cacheEntry = (xfGfxCacheEntry*) calloc(1, sizeof(xfGfxCacheEntry));
|
||||
|
||||
if (!cacheEntry)
|
||||
return -1;
|
||||
|
||||
cacheEntry->width = (UINT32) (rect->right - rect->left);
|
||||
cacheEntry->height = (UINT32) (rect->bottom - rect->top);
|
||||
cacheEntry->alpha = surface->alpha;
|
||||
|
||||
cacheEntry->scanline = (cacheEntry->width + (cacheEntry->width % 4)) * 4;
|
||||
cacheEntry->data = (BYTE*) calloc(1, surface->scanline * surface->height);
|
||||
|
||||
if (!cacheEntry->data)
|
||||
return -1;
|
||||
|
||||
freerdp_image_copy(cacheEntry->data, PIXEL_FORMAT_XRGB32, cacheEntry->scanline,
|
||||
0, 0, cacheEntry->width, cacheEntry->height, surface->data,
|
||||
PIXEL_FORMAT_XRGB32, surface->scanline, rect->left, rect->top);
|
||||
|
||||
context->SetCacheSlotData(context, surfaceToCache->cacheSlot, (void*) cacheEntry);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* cacheToSurface)
|
||||
{
|
||||
UINT16 index;
|
||||
RDPGFX_POINT16* destPt;
|
||||
xfGfxSurface* surface;
|
||||
xfGfxCacheEntry* cacheEntry;
|
||||
RECTANGLE_16 invalidRect;
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
surface = (xfGfxSurface*) context->GetSurfaceData(context, cacheToSurface->surfaceId);
|
||||
cacheEntry = (xfGfxCacheEntry*) context->GetCacheSlotData(context, cacheToSurface->cacheSlot);
|
||||
|
||||
//printf("xf_CacheToSurface: cacheEntry: %d\n",
|
||||
// cacheToSurface->cacheSlot);
|
||||
|
||||
if (!surface || !cacheEntry)
|
||||
return -1;
|
||||
|
||||
for (index = 0; index < cacheToSurface->destPtsCount; index++)
|
||||
{
|
||||
destPt = &cacheToSurface->destPts[index];
|
||||
|
||||
freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline,
|
||||
destPt->x, destPt->y, cacheEntry->width, cacheEntry->height,
|
||||
cacheEntry->data, PIXEL_FORMAT_XRGB32, cacheEntry->scanline, 0, 0);
|
||||
|
||||
invalidRect.left = destPt->x;
|
||||
invalidRect.top = destPt->y;
|
||||
invalidRect.right = destPt->x + cacheEntry->width - 1;
|
||||
invalidRect.bottom = destPt->y + cacheEntry->height - 1;
|
||||
|
||||
region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect);
|
||||
}
|
||||
|
||||
if (!xfc->inGfxFrame)
|
||||
xf_OutputUpdate(xfc);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_CacheImportReply(RdpgfxClientContext* context, RDPGFX_CACHE_IMPORT_REPLY_PDU* cacheImportReply)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PDU* evictCacheEntry)
|
||||
{
|
||||
xfGfxCacheEntry* cacheEntry;
|
||||
|
||||
//printf("xf_EvictCacheEntry\n");
|
||||
|
||||
cacheEntry = (xfGfxCacheEntry*) context->GetCacheSlotData(context, evictCacheEntry->cacheSlot);
|
||||
|
||||
if (cacheEntry)
|
||||
{
|
||||
free(cacheEntry->data);
|
||||
free(cacheEntry);
|
||||
}
|
||||
|
||||
context->SetCacheSlotData(context, evictCacheEntry->cacheSlot, NULL);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput)
|
||||
{
|
||||
xfContext* xfc = (xfContext*) context->custom;
|
||||
|
||||
xfc->outputSurfaceId = surfaceToOutput->surfaceId;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int xf_MapSurfaceToWindow(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* surfaceToWindow)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx)
|
||||
{
|
||||
xfc->gfx = gfx;
|
||||
gfx->custom = (void*) xfc;
|
||||
|
||||
gfx->ResetGraphics = xf_ResetGraphics;
|
||||
gfx->StartFrame = xf_StartFrame;
|
||||
gfx->EndFrame = xf_EndFrame;
|
||||
gfx->SurfaceCommand = xf_SurfaceCommand;
|
||||
gfx->DeleteEncodingContext = xf_DeleteEncodingContext;
|
||||
gfx->CreateSurface = xf_CreateSurface;
|
||||
gfx->DeleteSurface = xf_DeleteSurface;
|
||||
gfx->SolidFill = xf_SolidFill;
|
||||
gfx->SurfaceToSurface = xf_SurfaceToSurface;
|
||||
gfx->SurfaceToCache = xf_SurfaceToCache;
|
||||
gfx->CacheToSurface = xf_CacheToSurface;
|
||||
gfx->CacheImportReply = xf_CacheImportReply;
|
||||
gfx->EvictCacheEntry = xf_EvictCacheEntry;
|
||||
gfx->MapSurfaceToOutput = xf_MapSurfaceToOutput;
|
||||
gfx->MapSurfaceToWindow = xf_MapSurfaceToWindow;
|
||||
|
||||
region16_init(&(xfc->invalidRegion));
|
||||
}
|
||||
|
||||
void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx)
|
||||
{
|
||||
region16_uninit(&(xfc->invalidRegion));
|
||||
|
||||
gfx->custom = NULL;
|
||||
xfc->gfx = NULL;
|
||||
}
|
54
client/X11/xf_gfx.h
Normal file
54
client/X11/xf_gfx.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* X11 Graphics Pipeline
|
||||
*
|
||||
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __XF_GRAPHICS_PIPELINE_H
|
||||
#define __XF_GRAPHICS_PIPELINE_H
|
||||
|
||||
#include "xf_client.h"
|
||||
#include "xfreerdp.h"
|
||||
|
||||
struct xf_gfx_surface
|
||||
{
|
||||
UINT16 surfaceId;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
BOOL alpha;
|
||||
BYTE* data;
|
||||
XImage* image;
|
||||
int scanline;
|
||||
};
|
||||
typedef struct xf_gfx_surface xfGfxSurface;
|
||||
|
||||
struct xf_gfx_cache_entry
|
||||
{
|
||||
UINT64 cacheKey;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
BOOL alpha;
|
||||
BYTE* data;
|
||||
int scanline;
|
||||
};
|
||||
typedef struct xf_gfx_cache_entry xfGfxCacheEntry;
|
||||
|
||||
int xf_OutputExpose(xfContext* xfc, int x, int y, int width, int height);
|
||||
|
||||
void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx);
|
||||
void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx);
|
||||
|
||||
#endif /* __XF_GRAPHICS_PIPELINE_H */
|
@ -145,8 +145,8 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap,
|
||||
break;
|
||||
|
||||
case RDP_CODEC_ID_REMOTEFX:
|
||||
rfx_context_set_pixel_format(xfc->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8);
|
||||
msg = rfx_process_message(xfc->rfx_context, data, length);
|
||||
rfx_context_set_pixel_format(xfc->rfx, RDP_PIXEL_FORMAT_B8G8R8A8);
|
||||
msg = rfx_process_message(xfc->rfx, data, length);
|
||||
|
||||
if (msg == NULL)
|
||||
{
|
||||
@ -166,7 +166,7 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap,
|
||||
src++;
|
||||
}
|
||||
}
|
||||
rfx_message_free(xfc->rfx_context, msg);
|
||||
rfx_message_free(xfc->rfx, msg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -71,10 +71,12 @@ struct xf_window
|
||||
int bottom;
|
||||
int width;
|
||||
int height;
|
||||
int shmid;
|
||||
Window handle;
|
||||
Window *xfwin;
|
||||
BOOL fullscreen;
|
||||
BOOL decorations;
|
||||
rdpWindow* window;
|
||||
rdpWindow *window;
|
||||
BOOL is_mapped;
|
||||
BOOL is_transient;
|
||||
xfLocalMove local_move;
|
||||
@ -82,39 +84,39 @@ struct xf_window
|
||||
BOOL rail_ignore_configure;
|
||||
};
|
||||
|
||||
void xf_ewmhints_init(xfContext* xfc);
|
||||
void xf_ewmhints_init(xfContext *xfc);
|
||||
|
||||
BOOL xf_GetCurrentDesktop(xfContext* xfc);
|
||||
BOOL xf_GetWorkArea(xfContext* xfc);
|
||||
BOOL xf_GetCurrentDesktop(xfContext *xfc);
|
||||
BOOL xf_GetWorkArea(xfContext *xfc);
|
||||
|
||||
void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen);
|
||||
void xf_SetWindowDecorations(xfContext* xfc, xfWindow* window, BOOL show);
|
||||
void xf_SetWindowUnlisted(xfContext* xfc, xfWindow* window);
|
||||
void xf_SetWindowFullscreen(xfContext *xfc, xfWindow *window, BOOL fullscreen);
|
||||
void xf_SetWindowDecorations(xfContext *xfc, xfWindow *window, BOOL show);
|
||||
void xf_SetWindowUnlisted(xfContext *xfc, xfWindow *window);
|
||||
|
||||
xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, int height, BOOL decorations);
|
||||
void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, int height);
|
||||
xfWindow *xf_CreateDesktopWindow(xfContext *xfc, char *name, int width, int height, BOOL decorations);
|
||||
void xf_ResizeDesktopWindow(xfContext *xfc, xfWindow *window, int width, int height);
|
||||
|
||||
xfWindow* xf_CreateWindow(xfContext* xfc, rdpWindow* wnd, int x, int y, int width, int height, UINT32 id);
|
||||
void xf_SetWindowText(xfContext* xfc, xfWindow* window, char *name);
|
||||
void xf_MoveWindow(xfContext* xfc, xfWindow* window, int x, int y, int width, int height);
|
||||
void xf_ShowWindow(xfContext* xfc, xfWindow* window, BYTE state);
|
||||
void xf_SetWindowIcon(xfContext* xfc, xfWindow* window, rdpIcon* icon);
|
||||
void xf_SetWindowRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* rects, int nrects);
|
||||
void xf_SetWindowVisibilityRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* rects, int nrects);
|
||||
void xf_SetWindowStyle(xfContext* xfc, xfWindow* window, UINT32 style, UINT32 ex_style);
|
||||
void xf_UpdateWindowArea(xfContext* xfc, xfWindow* window, int x, int y, int width, int height);
|
||||
BOOL xf_IsWindowBorder(xfContext* xfc, xfWindow* xfw, int x, int y);
|
||||
void xf_DestroyWindow(xfContext* xfc, xfWindow* window);
|
||||
rdpWindow* xf_rdpWindowFromWindow(xfContext* xfc, Window wnd);
|
||||
xfWindow *xf_CreateWindow(xfContext *xfc, rdpWindow *wnd, int x, int y, int width, int height, UINT32 id);
|
||||
void xf_SetWindowText(xfContext *xfc, xfWindow *window, char *name);
|
||||
void xf_MoveWindow(xfContext *xfc, xfWindow *window, int x, int y, int width, int height);
|
||||
void xf_ShowWindow(xfContext *xfc, xfWindow *window, BYTE state);
|
||||
void xf_SetWindowIcon(xfContext *xfc, xfWindow *window, rdpIcon *icon);
|
||||
void xf_SetWindowRects(xfContext *xfc, xfWindow *window, RECTANGLE_16 *rects, int nrects);
|
||||
void xf_SetWindowVisibilityRects(xfContext *xfc, xfWindow *window, RECTANGLE_16 *rects, int nrects);
|
||||
void xf_SetWindowStyle(xfContext *xfc, xfWindow *window, UINT32 style, UINT32 ex_style);
|
||||
void xf_UpdateWindowArea(xfContext *xfc, xfWindow *window, int x, int y, int width, int height);
|
||||
BOOL xf_IsWindowBorder(xfContext *xfc, xfWindow *xfw, int x, int y);
|
||||
void xf_DestroyWindow(xfContext *xfc, xfWindow *window);
|
||||
rdpWindow *xf_rdpWindowFromWindow(xfContext *xfc, Window wnd);
|
||||
|
||||
BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int length,
|
||||
unsigned long* nitems, unsigned long* bytes, BYTE** prop);
|
||||
BOOL xf_GetWindowProperty(xfContext *xfc, Window window, Atom property, int length,
|
||||
unsigned long *nitems, unsigned long *bytes, BYTE **prop);
|
||||
|
||||
void xf_SetWindowMinMaxInfo(xfContext* xfc, xfWindow* window, int maxWidth, int maxHeight,
|
||||
int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight);
|
||||
void xf_SetWindowMinMaxInfo(xfContext *xfc, xfWindow *window, int maxWidth, int maxHeight,
|
||||
int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight);
|
||||
|
||||
void xf_StartLocalMoveSize(xfContext* xfc, xfWindow* window, int direction, int x, int y);
|
||||
void xf_EndLocalMoveSize(xfContext* xfc, xfWindow *window);
|
||||
void xf_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...);
|
||||
void xf_StartLocalMoveSize(xfContext *xfc, xfWindow *window, int direction, int x, int y);
|
||||
void xf_EndLocalMoveSize(xfContext *xfc, xfWindow *window);
|
||||
void xf_SendClientEvent(xfContext *xfc, xfWindow *window, Atom atom, unsigned int numArgs, ...);
|
||||
|
||||
#endif /* __XF_WINDOW_H */
|
||||
|
@ -28,6 +28,14 @@ typedef struct xf_context xfContext;
|
||||
#include "xf_monitor.h"
|
||||
#include "xf_channels.h"
|
||||
|
||||
#include <freerdp/gdi/gdi.h>
|
||||
#include <freerdp/codec/rfx.h>
|
||||
#include <freerdp/codec/nsc.h>
|
||||
#include <freerdp/codec/clear.h>
|
||||
#include <freerdp/codec/color.h>
|
||||
#include <freerdp/codec/bitmap.h>
|
||||
#include <freerdp/codec/region.h>
|
||||
|
||||
struct xf_WorkArea
|
||||
{
|
||||
UINT32 x;
|
||||
@ -103,6 +111,10 @@ struct xf_context
|
||||
|
||||
HGDI_DC hdc;
|
||||
BYTE* primary_buffer;
|
||||
REGION16 invalidRegion;
|
||||
BOOL inGfxFrame;
|
||||
BOOL graphicsReset;
|
||||
UINT16 outputSurfaceId;
|
||||
|
||||
BOOL frame_begin;
|
||||
UINT16 frame_x1;
|
||||
@ -137,8 +149,9 @@ struct xf_context
|
||||
VIRTUAL_SCREEN vscreen;
|
||||
BYTE* bmp_codec_none;
|
||||
BYTE* bmp_codec_nsc;
|
||||
void* rfx_context;
|
||||
void* nsc_context;
|
||||
RFX_CONTEXT* rfx;
|
||||
NSC_CONTEXT* nsc;
|
||||
CLEAR_CONTEXT* clear;
|
||||
void* xv_context;
|
||||
void* clipboard_context;
|
||||
|
||||
@ -168,6 +181,7 @@ struct xf_context
|
||||
|
||||
/* Channels */
|
||||
RdpeiClientContext* rdpei;
|
||||
RdpgfxClientContext* gfx;
|
||||
};
|
||||
|
||||
void xf_create_window(xfContext* xfc);
|
||||
|
@ -814,6 +814,38 @@ int freerdp_parse_username(char* username, char** user, char** domain)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int freerdp_parse_hostname(char* hostname, char** host, int* port)
|
||||
{
|
||||
char* p;
|
||||
int length;
|
||||
|
||||
p = strrchr(hostname, ':');
|
||||
|
||||
if (p)
|
||||
{
|
||||
length = (p - hostname);
|
||||
*host = (char*) malloc(length + 1);
|
||||
|
||||
if (!(*host))
|
||||
return -1;
|
||||
|
||||
CopyMemory(*host, hostname, length);
|
||||
(*host)[length] = '\0';
|
||||
*port = atoi(p + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*host = _strdup(hostname);
|
||||
|
||||
if (!(*host))
|
||||
return -1;
|
||||
|
||||
*port = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int freerdp_set_connection_type(rdpSettings* settings, int type)
|
||||
{
|
||||
settings->ConnectionType = type;
|
||||
@ -1577,6 +1609,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings,
|
||||
CommandLineSwitchCase(arg, "gfx")
|
||||
{
|
||||
settings->SupportGraphicsPipeline = TRUE;
|
||||
settings->FastPathOutput = TRUE;
|
||||
settings->ColorDepth = 32;
|
||||
settings->LargePointerFlag = TRUE;
|
||||
settings->FrameMarkerCommandEnabled = TRUE;
|
||||
}
|
||||
CommandLineSwitchCase(arg, "rfx")
|
||||
{
|
||||
|
@ -63,7 +63,7 @@ BOOL freerdp_client_rdp_file_set_integer(rdpFile* file, const char* name, int va
|
||||
file->ScreenModeId = value;
|
||||
else if (_stricmp(name, "span monitors") == 0)
|
||||
file->SpanMonitors = value;
|
||||
else if (_stricmp(name, "smartsizing") == 0)
|
||||
else if (_stricmp(name, "smart sizing") == 0)
|
||||
file->SmartSizing = value;
|
||||
else if (_stricmp(name, "enablesuperpan") == 0)
|
||||
file->EnableSuperSpan = value;
|
||||
@ -767,10 +767,23 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
|
||||
free(domain);
|
||||
}
|
||||
|
||||
if (~((size_t) file->FullAddress))
|
||||
{
|
||||
int port = -1;
|
||||
char* host = NULL;
|
||||
|
||||
freerdp_parse_hostname(file->FullAddress, &host, &port);
|
||||
|
||||
freerdp_set_param_string(settings, FreeRDP_ServerHostname, host);
|
||||
|
||||
if (port > 0)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_ServerPort, (UINT32) port);
|
||||
|
||||
free(host);
|
||||
}
|
||||
|
||||
if (~file->ServerPort)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_ServerPort, file->ServerPort);
|
||||
if (~((size_t) file->FullAddress))
|
||||
freerdp_set_param_string(settings, FreeRDP_ServerHostname, file->FullAddress);
|
||||
|
||||
if (~file->DesktopWidth)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_DesktopWidth, file->DesktopWidth);
|
||||
@ -802,12 +815,12 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
|
||||
*
|
||||
* Values:
|
||||
*
|
||||
* 0: The remote session will appear in a window.
|
||||
* 1: The remote session will appear full screen.
|
||||
* 1: The remote session will appear in a window.
|
||||
* 2: The remote session will appear full screen.
|
||||
*/
|
||||
|
||||
freerdp_set_param_bool(settings, FreeRDP_Fullscreen,
|
||||
(file->ScreenModeId == 1) ? TRUE : FALSE);
|
||||
(file->ScreenModeId == 2) ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
if (~((size_t) file->SmartSizing))
|
||||
@ -867,7 +880,19 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
|
||||
freerdp_set_param_bool(settings, FreeRDP_CompressionEnabled, file->Compression);
|
||||
|
||||
if (~((size_t) file->GatewayHostname))
|
||||
freerdp_set_param_string(settings, FreeRDP_GatewayHostname, file->GatewayHostname);
|
||||
{
|
||||
int port = -1;
|
||||
char* host = NULL;
|
||||
|
||||
freerdp_parse_hostname(file->GatewayHostname, &host, &port);
|
||||
|
||||
freerdp_set_param_string(settings, FreeRDP_GatewayHostname, host);
|
||||
|
||||
if (port > 0)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_GatewayPort, (UINT32) port);
|
||||
|
||||
free(host);
|
||||
}
|
||||
|
||||
if (~file->GatewayUsageMethod)
|
||||
freerdp_set_gateway_usage_method(settings, file->GatewayUsageMethod);
|
||||
|
@ -303,12 +303,11 @@ void ios_freerdp_free(freerdp* instance)
|
||||
void ios_init_freerdp()
|
||||
{
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
freerdp_channels_global_init();
|
||||
freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0);
|
||||
}
|
||||
|
||||
void ios_uninit_freerdp()
|
||||
{
|
||||
freerdp_channels_global_uninit();
|
||||
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,7 @@ option(WITH_DEBUG_CAPABILITIES "Print capability negotiation debug messages." ${
|
||||
option(WITH_DEBUG_CHANNELS "Print channel manager debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_CLIPRDR "Print clipboard redirection debug messages" ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_DVC "Print dynamic virtual channel debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_TSMF "Print TSMF virtual channel debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_GDI "Print graphics debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_KBD "Print keyboard related debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_LICENSE "Print license debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
|
@ -27,7 +27,7 @@ option(ANDROID_BUILD_JAVA "Automatically android java code - build type depends
|
||||
option(ANDROID_BUILD_JAVA_DEBUG "Create a android debug package" ${JAVA_DEBUG_DEFAULT})
|
||||
|
||||
set(ANDROID_APP_VERSION 3 CACHE STRING "Application version")
|
||||
set(ANDROID_APP_TARGET_SDK 11 CACHE STRING "Application target android SDK")
|
||||
set(ANDROID_APP_TARGET_SDK 14 CACHE STRING "Application target android SDK")
|
||||
set(ANDROID_APP_MIN_SDK 9 CACHE STRING "Application minimum android SDK requirement")
|
||||
set(ANDROID_APP_GOOGLE_TARGET_SDK "16" CACHE STRING "Application target google SDK")
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user