Merge pull request #2697 from realjiangms/shadow_audio
Shadow server: fix channel disposal and add audio support. fix message mechanism in client
This commit is contained in:
commit
750e752d45
@ -31,6 +31,8 @@
|
||||
|
||||
#include <freerdp/server/encomsp.h>
|
||||
#include <freerdp/server/remdesk.h>
|
||||
#include <freerdp/server/rdpsnd.h>
|
||||
#include <freerdp/server/audin.h>
|
||||
|
||||
#include <freerdp/codec/color.h>
|
||||
#include <freerdp/codec/region.h>
|
||||
@ -73,6 +75,8 @@ typedef int (*pfnShadowUnicodeKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT
|
||||
typedef int (*pfnShadowMouseEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y);
|
||||
typedef int (*pfnShadowExtendedMouseEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 x, UINT16 y);
|
||||
|
||||
typedef void (*pfnShadowChannelAudinServerReceiveSamples)(rdpShadowSubsystem* subsystem, const void* buf, int nframes);
|
||||
|
||||
struct rdp_shadow_client
|
||||
{
|
||||
rdpContext context;
|
||||
@ -82,7 +86,7 @@ struct rdp_shadow_client
|
||||
BOOL inLobby;
|
||||
BOOL mayView;
|
||||
BOOL mayInteract;
|
||||
HANDLE StopEvent;
|
||||
wMessageQueue* MsgQueue;
|
||||
CRITICAL_SECTION lock;
|
||||
REGION16 invalidRegion;
|
||||
rdpShadowServer* server;
|
||||
@ -96,6 +100,8 @@ struct rdp_shadow_client
|
||||
HANDLE vcm;
|
||||
EncomspServerContext* encomsp;
|
||||
RemdeskServerContext* remdesk;
|
||||
RdpsndServerContext* rdpsnd;
|
||||
audin_server_context* audin;
|
||||
};
|
||||
|
||||
struct rdp_shadow_server
|
||||
@ -153,11 +159,17 @@ struct _RDP_SHADOW_ENTRY_POINTS
|
||||
UINT32 pointerX; \
|
||||
UINT32 pointerY; \
|
||||
\
|
||||
const AUDIO_FORMAT* rdpsndFormats; \
|
||||
int nRdpsndFormats; \
|
||||
const AUDIO_FORMAT* audinFormats; \
|
||||
int nAudinFormats; \
|
||||
\
|
||||
pfnShadowSynchronizeEvent SynchronizeEvent; \
|
||||
pfnShadowKeyboardEvent KeyboardEvent; \
|
||||
pfnShadowUnicodeKeyboardEvent UnicodeKeyboardEvent; \
|
||||
pfnShadowMouseEvent MouseEvent; \
|
||||
pfnShadowExtendedMouseEvent ExtendedMouseEvent; \
|
||||
pfnShadowChannelAudinServerReceiveSamples AudinServerReceiveSamples; \
|
||||
\
|
||||
pfnShadowAuthenticate Authenticate; \
|
||||
pfnShadowClientConnect ClientConnect; \
|
||||
@ -170,6 +182,79 @@ struct rdp_shadow_subsystem
|
||||
RDP_SHADOW_SUBSYSTEM_COMMON();
|
||||
};
|
||||
|
||||
/* Definition of message between subsystem and clients */
|
||||
#define SHADOW_MSG_IN_REFRESH_OUTPUT_ID 1001
|
||||
#define SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID 1002
|
||||
|
||||
struct _SHADOW_MSG_IN_REFRESH_OUTPUT
|
||||
{
|
||||
UINT32 numRects;
|
||||
RECTANGLE_16* rects;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_IN_REFRESH_OUTPUT SHADOW_MSG_IN_REFRESH_OUTPUT;
|
||||
|
||||
struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT
|
||||
{
|
||||
BOOL allow;
|
||||
RECTANGLE_16 rect;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT;
|
||||
|
||||
typedef struct _SHADOW_MSG_OUT SHADOW_MSG_OUT;
|
||||
typedef void (*MSG_OUT_FREE_FN)(UINT32 id, SHADOW_MSG_OUT* msg);
|
||||
#define RDP_SHADOW_MSG_OUT_COMMON() \
|
||||
int refCount; \
|
||||
MSG_OUT_FREE_FN Free; /* function to free SHADOW_MSG_OUT */
|
||||
|
||||
struct _SHADOW_MSG_OUT
|
||||
{
|
||||
RDP_SHADOW_MSG_OUT_COMMON();
|
||||
};
|
||||
|
||||
#define SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID 2001
|
||||
#define SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID 2002
|
||||
#define SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID 2003
|
||||
#define SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID 2004
|
||||
|
||||
struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE
|
||||
{
|
||||
RDP_SHADOW_MSG_OUT_COMMON();
|
||||
UINT32 xPos;
|
||||
UINT32 yPos;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE SHADOW_MSG_OUT_POINTER_POSITION_UPDATE;
|
||||
|
||||
struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE
|
||||
{
|
||||
RDP_SHADOW_MSG_OUT_COMMON();
|
||||
UINT32 xHot;
|
||||
UINT32 yHot;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
BYTE* pixels;
|
||||
int scanline;
|
||||
BOOL premultiplied;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE;
|
||||
|
||||
struct _SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES
|
||||
{
|
||||
RDP_SHADOW_MSG_OUT_COMMON();
|
||||
AUDIO_FORMAT audio_format;
|
||||
void* buf;
|
||||
int nFrames;
|
||||
UINT16 wTimestamp;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES;
|
||||
|
||||
struct _SHADOW_MSG_OUT_AUDIO_OUT_VOLUME
|
||||
{
|
||||
RDP_SHADOW_MSG_OUT_COMMON();
|
||||
int left;
|
||||
int right;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_OUT_AUDIO_OUT_VOLUME SHADOW_MSG_OUT_AUDIO_OUT_VOLUME;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -190,6 +275,10 @@ FREERDP_API int shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors);
|
||||
FREERDP_API rdpShadowServer* shadow_server_new();
|
||||
FREERDP_API void shadow_server_free(rdpShadowServer* server);
|
||||
|
||||
FREERDP_API BOOL shadow_client_post_msg(rdpShadowClient* client, void* context, UINT32 type, SHADOW_MSG_OUT* msg, void* lParam);
|
||||
FREERDP_API int shadow_client_boardcast_msg(rdpShadowServer* server, void* context, UINT32 type, SHADOW_MSG_OUT* msg, void* lParam);
|
||||
FREERDP_API int shadow_client_boardcast_quit(rdpShadowServer* server, int nExitCode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -169,6 +169,10 @@ set(${MODULE_PREFIX}_SRCS
|
||||
shadow_encomsp.h
|
||||
shadow_remdesk.c
|
||||
shadow_remdesk.h
|
||||
shadow_rdpsnd.c
|
||||
shadow_rdpsnd.h
|
||||
shadow_audin.c
|
||||
shadow_audin.h
|
||||
shadow_subsystem.c
|
||||
shadow_subsystem.h
|
||||
shadow_mcevent.c
|
||||
|
@ -452,48 +452,56 @@ int mac_shadow_screen_grab(macShadowSubsystem* subsystem)
|
||||
|
||||
int mac_shadow_subsystem_process_message(macShadowSubsystem* subsystem, wMessage* message)
|
||||
{
|
||||
if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID)
|
||||
switch(message->id)
|
||||
{
|
||||
UINT32 index;
|
||||
SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
|
||||
|
||||
if (msg->numRects)
|
||||
case SHADOW_MSG_IN_REFRESH_OUTPUT_ID:
|
||||
{
|
||||
for (index = 0; index < msg->numRects; index++)
|
||||
UINT32 index;
|
||||
SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
|
||||
|
||||
if (msg->numRects)
|
||||
{
|
||||
for (index = 0; index < msg->numRects; index++)
|
||||
{
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &msg->rects[index]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RECTANGLE_16 refreshRect;
|
||||
|
||||
refreshRect.left = 0;
|
||||
refreshRect.top = 0;
|
||||
refreshRect.right = subsystem->width;
|
||||
refreshRect.bottom = subsystem->height;
|
||||
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &refreshRect);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID:
|
||||
{
|
||||
SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
|
||||
|
||||
subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE;
|
||||
|
||||
if (msg->allow)
|
||||
{
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &msg->rects[index]);
|
||||
&(subsystem->invalidRegion), &(msg->rect));
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
RECTANGLE_16 refreshRect;
|
||||
|
||||
refreshRect.left = 0;
|
||||
refreshRect.top = 0;
|
||||
refreshRect.right = subsystem->width;
|
||||
refreshRect.bottom = subsystem->height;
|
||||
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &refreshRect);
|
||||
}
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown message id: %u", message->id);
|
||||
break;
|
||||
}
|
||||
else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID)
|
||||
{
|
||||
SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
|
||||
|
||||
subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE;
|
||||
|
||||
if (msg->allow)
|
||||
{
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &(msg->rect));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (message->Free)
|
||||
message->Free(message);
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -348,11 +348,30 @@ void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16
|
||||
#endif
|
||||
}
|
||||
|
||||
static void x11_shadow_message_free(UINT32 id, SHADOW_MSG_OUT* msg)
|
||||
{
|
||||
switch(id)
|
||||
{
|
||||
case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
|
||||
free(msg);
|
||||
break;
|
||||
|
||||
case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
|
||||
free(((SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)msg)->pixels);
|
||||
free(msg);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown message id: %u", id);
|
||||
free(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int x11_shadow_pointer_position_update(x11ShadowSubsystem* subsystem)
|
||||
{
|
||||
SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg;
|
||||
UINT32 msgId = SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID;
|
||||
wMessagePipe* MsgPipe = subsystem->MsgPipe;
|
||||
|
||||
msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_POSITION_UPDATE));
|
||||
|
||||
@ -361,15 +380,15 @@ int x11_shadow_pointer_position_update(x11ShadowSubsystem* subsystem)
|
||||
|
||||
msg->xPos = subsystem->pointerX;
|
||||
msg->yPos = subsystem->pointerY;
|
||||
msg->Free = x11_shadow_message_free;
|
||||
|
||||
return MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL) ? 1 : -1;
|
||||
return shadow_client_boardcast_msg(subsystem->server, NULL, msgId, (SHADOW_MSG_OUT*) msg, NULL) ? 1 : -1;
|
||||
}
|
||||
|
||||
int x11_shadow_pointer_alpha_update(x11ShadowSubsystem* subsystem)
|
||||
{
|
||||
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg;
|
||||
UINT32 msgId = SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID;
|
||||
wMessagePipe* MsgPipe = subsystem->MsgPipe;
|
||||
|
||||
msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE));
|
||||
|
||||
@ -392,8 +411,9 @@ int x11_shadow_pointer_alpha_update(x11ShadowSubsystem* subsystem)
|
||||
|
||||
CopyMemory(msg->pixels, subsystem->cursorPixels, msg->scanline * msg->height);
|
||||
msg->premultiplied = TRUE;
|
||||
msg->Free = x11_shadow_message_free;
|
||||
|
||||
return MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL) ? 1 : -1;
|
||||
return shadow_client_boardcast_msg(subsystem->server, NULL, msgId, (SHADOW_MSG_OUT*) msg, NULL) ? 1 : -1;
|
||||
}
|
||||
|
||||
int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
|
||||
@ -730,43 +750,51 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
|
||||
|
||||
int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage* message)
|
||||
{
|
||||
if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID)
|
||||
switch(message->id)
|
||||
{
|
||||
UINT32 index;
|
||||
SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
|
||||
|
||||
if (msg->numRects)
|
||||
case SHADOW_MSG_IN_REFRESH_OUTPUT_ID:
|
||||
{
|
||||
for (index = 0; index < msg->numRects; index++)
|
||||
UINT32 index;
|
||||
SHADOW_MSG_IN_REFRESH_OUTPUT* msg = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
|
||||
|
||||
if (msg->numRects)
|
||||
{
|
||||
for (index = 0; index < msg->numRects; index++)
|
||||
{
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &msg->rects[index]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RECTANGLE_16 refreshRect;
|
||||
|
||||
refreshRect.left = 0;
|
||||
refreshRect.top = 0;
|
||||
refreshRect.right = subsystem->width;
|
||||
refreshRect.bottom = subsystem->height;
|
||||
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &refreshRect);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID:
|
||||
{
|
||||
SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
|
||||
|
||||
subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE;
|
||||
|
||||
if (msg->allow)
|
||||
{
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &msg->rects[index]);
|
||||
&(subsystem->invalidRegion), &(msg->rect));
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
RECTANGLE_16 refreshRect;
|
||||
|
||||
refreshRect.left = 0;
|
||||
refreshRect.top = 0;
|
||||
refreshRect.right = subsystem->width;
|
||||
refreshRect.bottom = subsystem->height;
|
||||
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &refreshRect);
|
||||
}
|
||||
}
|
||||
else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID)
|
||||
{
|
||||
SHADOW_MSG_IN_SUPPRESS_OUTPUT* msg = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
|
||||
|
||||
subsystem->suppressOutput = (msg->allow) ? FALSE : TRUE;
|
||||
|
||||
if (msg->allow)
|
||||
{
|
||||
region16_union_rect(&(subsystem->invalidRegion),
|
||||
&(subsystem->invalidRegion), &(msg->rect));
|
||||
}
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown message id: %u", message->id);
|
||||
break;
|
||||
}
|
||||
|
||||
if (message->Free)
|
||||
|
121
server/shadow/shadow_audin.c
Normal file
121
server/shadow/shadow_audin.c
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.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 <freerdp/log.h>
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_audin.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow")
|
||||
|
||||
/* Default supported audio formats */
|
||||
static const AUDIO_FORMAT default_supported_audio_formats[] =
|
||||
{
|
||||
{ WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0, NULL },
|
||||
{ WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, 0, NULL }
|
||||
};
|
||||
|
||||
static void AudinServerOpening(audin_server_context* context)
|
||||
{
|
||||
AUDIO_FORMAT* agreed_format = NULL;
|
||||
int i = 0, j = 0;
|
||||
for (i = 0; i < context->num_client_formats; i++)
|
||||
{
|
||||
for (j = 0; j < context->num_server_formats; j++)
|
||||
{
|
||||
if ((context->client_formats[i].wFormatTag == context->server_formats[j].wFormatTag) &&
|
||||
(context->client_formats[i].nChannels == context->server_formats[j].nChannels) &&
|
||||
(context->client_formats[i].nSamplesPerSec == context->server_formats[j].nSamplesPerSec))
|
||||
{
|
||||
agreed_format = (AUDIO_FORMAT*) &context->server_formats[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (agreed_format != NULL)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (agreed_format == NULL)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not agree on a audio format with the server\n");
|
||||
return;
|
||||
}
|
||||
|
||||
context->SelectFormat(context, i);
|
||||
}
|
||||
static void AudinServerOpenResult(audin_server_context* context, UINT32 result)
|
||||
{
|
||||
WLog_INFO(TAG, "AUDIN open result %u.\n", result);
|
||||
}
|
||||
static void AudinServerReceiveSamples(audin_server_context* context, const void* buf, int nframes)
|
||||
{
|
||||
rdpShadowClient* client = (rdpShadowClient* )context->data;
|
||||
rdpShadowSubsystem* subsystem = client->server->subsystem;
|
||||
|
||||
if (!client->mayInteract)
|
||||
return;
|
||||
|
||||
if (subsystem->AudinServerReceiveSamples)
|
||||
subsystem->AudinServerReceiveSamples(subsystem, buf, nframes);
|
||||
}
|
||||
|
||||
int shadow_client_audin_init(rdpShadowClient* client)
|
||||
{
|
||||
audin_server_context* audin;
|
||||
audin = client->audin = audin_server_context_new(client->vcm);
|
||||
if (!audin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
audin->data = client;
|
||||
|
||||
if (client->subsystem->audinFormats)
|
||||
{
|
||||
audin->server_formats = client->subsystem->audinFormats;
|
||||
audin->num_server_formats = client->subsystem->nAudinFormats;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set default audio formats. */
|
||||
audin->server_formats = default_supported_audio_formats;
|
||||
audin->num_server_formats = sizeof(default_supported_audio_formats) / sizeof(default_supported_audio_formats[0]);
|
||||
}
|
||||
|
||||
audin->dst_format = audin->server_formats[0];
|
||||
|
||||
audin->Opening = AudinServerOpening;
|
||||
audin->OpenResult = AudinServerOpenResult;
|
||||
audin->ReceiveSamples = AudinServerReceiveSamples;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void shadow_client_audin_uninit(rdpShadowClient* client)
|
||||
{
|
||||
if (client->audin)
|
||||
{
|
||||
audin_server_context_free(client->audin);
|
||||
client->audin = NULL;
|
||||
}
|
||||
}
|
38
server/shadow/shadow_audin.h
Normal file
38
server/shadow/shadow_audin.h
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.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 FREERDP_SHADOW_SERVER_AUDIN_H
|
||||
#define FREERDP_SHADOW_SERVER_AUDIN_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int shadow_client_audin_init(rdpShadowClient* client);
|
||||
void shadow_client_audin_uninit(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SHADOW_SERVER_AUDIN_H */
|
@ -36,5 +36,23 @@ int shadow_client_channels_post_connect(rdpShadowClient* client)
|
||||
shadow_client_remdesk_init(client);
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelManagerIsChannelJoined(client->vcm, "rdpsnd"))
|
||||
{
|
||||
shadow_client_rdpsnd_init(client);
|
||||
}
|
||||
|
||||
shadow_client_audin_init(client);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void shadow_client_channels_free(rdpShadowClient* client)
|
||||
{
|
||||
shadow_client_audin_uninit(client);
|
||||
|
||||
shadow_client_rdpsnd_uninit(client);
|
||||
|
||||
shadow_client_remdesk_uninit(client);
|
||||
|
||||
shadow_client_encomsp_uninit(client);
|
||||
}
|
||||
|
@ -26,12 +26,15 @@
|
||||
|
||||
#include "shadow_encomsp.h"
|
||||
#include "shadow_remdesk.h"
|
||||
#include "shadow_rdpsnd.h"
|
||||
#include "shadow_audin.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int shadow_client_channels_post_connect(rdpShadowClient* client);
|
||||
void shadow_client_channels_free(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
#include <winpr/interlocked.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
@ -33,10 +34,21 @@
|
||||
|
||||
#define TAG CLIENT_TAG("shadow")
|
||||
|
||||
static void shadow_client_free_queued_message(void *obj)
|
||||
{
|
||||
wMessage *message = (wMessage*)obj;
|
||||
if (message->Free)
|
||||
{
|
||||
message->Free(message);
|
||||
message->Free = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
|
||||
{
|
||||
rdpSettings* settings;
|
||||
rdpShadowServer* server;
|
||||
const wObject cb = { NULL, NULL, NULL, shadow_client_free_queued_message, NULL };
|
||||
|
||||
server = (rdpShadowServer*) peer->ContextExtra;
|
||||
client->server = server;
|
||||
@ -89,8 +101,8 @@ BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
|
||||
if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
|
||||
goto fail_open_server;
|
||||
|
||||
if (!(client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||
goto fail_stop_event;
|
||||
if (!(client->MsgQueue = MessageQueue_New(&cb)))
|
||||
goto fail_message_queue;
|
||||
|
||||
if (!(client->encoder = shadow_encoder_new(client)))
|
||||
goto fail_encoder_new;
|
||||
@ -101,9 +113,9 @@ BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
|
||||
shadow_encoder_free(client->encoder);
|
||||
client->encoder = NULL;
|
||||
fail_encoder_new:
|
||||
CloseHandle(client->StopEvent);
|
||||
client->StopEvent = NULL;
|
||||
fail_stop_event:
|
||||
MessageQueue_Free(client->MsgQueue);
|
||||
client->MsgQueue = NULL;
|
||||
fail_message_queue:
|
||||
WTSCloseServer((HANDLE) client->vcm);
|
||||
client->vcm = NULL;
|
||||
fail_open_server:
|
||||
@ -134,7 +146,9 @@ void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
|
||||
|
||||
WTSCloseServer((HANDLE) client->vcm);
|
||||
|
||||
CloseHandle(client->StopEvent);
|
||||
/* Clear queued messages and free resource */
|
||||
MessageQueue_Clear(client->MsgQueue);
|
||||
MessageQueue_Free(client->MsgQueue);
|
||||
|
||||
if (client->lobby)
|
||||
{
|
||||
@ -147,25 +161,25 @@ void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
|
||||
shadow_encoder_free(client->encoder);
|
||||
client->encoder = NULL;
|
||||
}
|
||||
|
||||
shadow_client_encomsp_uninit(client);
|
||||
|
||||
shadow_client_remdesk_uninit(client);
|
||||
}
|
||||
|
||||
void shadow_client_message_free(wMessage* message)
|
||||
{
|
||||
if (message->id == SHADOW_MSG_IN_REFRESH_OUTPUT_ID)
|
||||
switch(message->id)
|
||||
{
|
||||
SHADOW_MSG_IN_REFRESH_OUTPUT* wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) message->wParam;
|
||||
case SHADOW_MSG_IN_REFRESH_OUTPUT_ID:
|
||||
free(((SHADOW_MSG_IN_REFRESH_OUTPUT*)message->wParam)->rects);
|
||||
free(message->wParam);
|
||||
break;
|
||||
|
||||
free(wParam->rects);
|
||||
free(wParam);
|
||||
}
|
||||
else if (message->id == SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID)
|
||||
{
|
||||
SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) message->wParam;
|
||||
free(wParam);
|
||||
case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID:
|
||||
free(message->wParam);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown message id: %u", message->id);
|
||||
free(message->wParam);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -889,63 +903,87 @@ int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* m
|
||||
|
||||
/* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
|
||||
|
||||
if (message->id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID)
|
||||
switch(message->id)
|
||||
{
|
||||
POINTER_POSITION_UPDATE pointerPosition;
|
||||
SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) message->wParam;
|
||||
|
||||
pointerPosition.xPos = msg->xPos;
|
||||
pointerPosition.yPos = msg->yPos;
|
||||
|
||||
if (client->activated)
|
||||
case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
|
||||
{
|
||||
if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
|
||||
POINTER_POSITION_UPDATE pointerPosition;
|
||||
SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) message->wParam;
|
||||
|
||||
pointerPosition.xPos = msg->xPos;
|
||||
pointerPosition.yPos = msg->yPos;
|
||||
|
||||
if (client->activated)
|
||||
{
|
||||
IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
|
||||
if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
|
||||
{
|
||||
IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
|
||||
|
||||
client->pointerX = msg->xPos;
|
||||
client->pointerY = msg->yPos;
|
||||
client->pointerX = msg->xPos;
|
||||
client->pointerY = msg->yPos;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
free(msg);
|
||||
}
|
||||
else if (message->id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID)
|
||||
{
|
||||
POINTER_NEW_UPDATE pointerNew;
|
||||
POINTER_COLOR_UPDATE* pointerColor;
|
||||
POINTER_CACHED_UPDATE pointerCached;
|
||||
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) message->wParam;
|
||||
|
||||
ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE));
|
||||
|
||||
pointerNew.xorBpp = 24;
|
||||
pointerColor = &(pointerNew.colorPtrAttr);
|
||||
|
||||
pointerColor->cacheIndex = 0;
|
||||
pointerColor->xPos = msg->xHot;
|
||||
pointerColor->yPos = msg->yHot;
|
||||
pointerColor->width = msg->width;
|
||||
pointerColor->height = msg->height;
|
||||
|
||||
pointerCached.cacheIndex = pointerColor->cacheIndex;
|
||||
|
||||
if (client->activated)
|
||||
case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
|
||||
{
|
||||
shadow_client_convert_alpha_pointer_data(msg->pixels, msg->premultiplied,
|
||||
msg->width, msg->height, pointerColor);
|
||||
POINTER_NEW_UPDATE pointerNew;
|
||||
POINTER_COLOR_UPDATE* pointerColor;
|
||||
POINTER_CACHED_UPDATE pointerCached;
|
||||
SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) message->wParam;
|
||||
|
||||
IFCALL(update->pointer->PointerNew, context, &pointerNew);
|
||||
IFCALL(update->pointer->PointerCached, context, &pointerCached);
|
||||
ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE));
|
||||
|
||||
free(pointerColor->xorMaskData);
|
||||
free(pointerColor->andMaskData);
|
||||
pointerNew.xorBpp = 24;
|
||||
pointerColor = &(pointerNew.colorPtrAttr);
|
||||
|
||||
pointerColor->cacheIndex = 0;
|
||||
pointerColor->xPos = msg->xHot;
|
||||
pointerColor->yPos = msg->yHot;
|
||||
pointerColor->width = msg->width;
|
||||
pointerColor->height = msg->height;
|
||||
|
||||
pointerCached.cacheIndex = pointerColor->cacheIndex;
|
||||
|
||||
if (client->activated)
|
||||
{
|
||||
shadow_client_convert_alpha_pointer_data(msg->pixels, msg->premultiplied,
|
||||
msg->width, msg->height, pointerColor);
|
||||
|
||||
IFCALL(update->pointer->PointerNew, context, &pointerNew);
|
||||
IFCALL(update->pointer->PointerCached, context, &pointerCached);
|
||||
|
||||
free(pointerColor->xorMaskData);
|
||||
free(pointerColor->andMaskData);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
free(msg->pixels);
|
||||
free(msg);
|
||||
case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
|
||||
{
|
||||
SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES* msg = (SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES*) message->wParam;
|
||||
if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
|
||||
{
|
||||
client->rdpsnd->src_format = msg->audio_format;
|
||||
IFCALL(client->rdpsnd->SendSamples, client->rdpsnd, msg->buf, msg->nFrames, msg->wTimestamp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
|
||||
{
|
||||
SHADOW_MSG_OUT_AUDIO_OUT_VOLUME* msg = (SHADOW_MSG_OUT_AUDIO_OUT_VOLUME*) message->wParam;
|
||||
if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
|
||||
{
|
||||
IFCALL(client->rdpsnd->SetVolume, client->rdpsnd, msg->left, msg->right);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown message id: %u", message->id);
|
||||
break;
|
||||
}
|
||||
|
||||
shadow_client_free_queued_message(message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -954,8 +992,10 @@ void* shadow_client_thread(rdpShadowClient* client)
|
||||
DWORD status;
|
||||
DWORD nCount;
|
||||
wMessage message;
|
||||
wMessage pointerPositionMsg;
|
||||
wMessage pointerAlphaMsg;
|
||||
wMessage audioVolumeMsg;
|
||||
HANDLE events[32];
|
||||
HANDLE StopEvent;
|
||||
HANDLE ClientEvent;
|
||||
HANDLE ChannelEvent;
|
||||
void* UpdateSubscriber;
|
||||
@ -967,7 +1007,7 @@ void* shadow_client_thread(rdpShadowClient* client)
|
||||
rdpShadowScreen* screen;
|
||||
rdpShadowEncoder* encoder;
|
||||
rdpShadowSubsystem* subsystem;
|
||||
wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
|
||||
wMessageQueue* MsgQueue = client->MsgQueue;
|
||||
|
||||
server = client->server;
|
||||
screen = server->screen;
|
||||
@ -990,14 +1030,13 @@ void* shadow_client_thread(rdpShadowClient* client)
|
||||
peer->update->SuppressOutput = (pSuppressOutput)shadow_client_suppress_output;
|
||||
peer->update->SurfaceFrameAcknowledge = (pSurfaceFrameAcknowledge)shadow_client_surface_frame_acknowledge;
|
||||
|
||||
if ((!client->StopEvent) || (!client->vcm) || (!subsystem->updateEvent))
|
||||
if ((!client->vcm) || (!subsystem->updateEvent))
|
||||
goto out;
|
||||
|
||||
UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
|
||||
if (!UpdateSubscriber)
|
||||
goto out;
|
||||
|
||||
StopEvent = client->StopEvent;
|
||||
UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
|
||||
ClientEvent = peer->GetEventHandle(peer);
|
||||
ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
|
||||
@ -1005,19 +1044,13 @@ void* shadow_client_thread(rdpShadowClient* client)
|
||||
while (1)
|
||||
{
|
||||
nCount = 0;
|
||||
events[nCount++] = StopEvent;
|
||||
events[nCount++] = UpdateEvent;
|
||||
events[nCount++] = ClientEvent;
|
||||
events[nCount++] = ChannelEvent;
|
||||
events[nCount++] = MessageQueue_Event(MsgPipe->Out);
|
||||
events[nCount++] = MessageQueue_Event(MsgQueue);
|
||||
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
|
||||
if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
if (client->activated)
|
||||
@ -1061,18 +1094,78 @@ void* shadow_client_thread(rdpShadowClient* client)
|
||||
}
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(MessageQueue_Event(MsgPipe->Out), 0) == WAIT_OBJECT_0)
|
||||
if (WaitForSingleObject(MessageQueue_Event(MsgQueue), 0) == WAIT_OBJECT_0)
|
||||
{
|
||||
if (MessageQueue_Peek(MsgPipe->Out, &message, TRUE))
|
||||
/* Drain messages. Pointer update could be accumulated. */
|
||||
pointerPositionMsg.id = 0;
|
||||
pointerPositionMsg.Free= NULL;
|
||||
pointerAlphaMsg.id = 0;
|
||||
pointerAlphaMsg.Free = NULL;
|
||||
audioVolumeMsg.id = 0;
|
||||
audioVolumeMsg.Free = NULL;
|
||||
while (MessageQueue_Peek(MsgQueue, &message, TRUE))
|
||||
{
|
||||
if (message.id == WMQ_QUIT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
shadow_client_subsystem_process_message(client, &message);
|
||||
switch(message.id)
|
||||
{
|
||||
case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
|
||||
/* Abandon previous message */
|
||||
shadow_client_free_queued_message(&pointerPositionMsg);
|
||||
CopyMemory(&pointerPositionMsg, &message, sizeof(wMessage));
|
||||
break;
|
||||
|
||||
case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
|
||||
/* Abandon previous message */
|
||||
shadow_client_free_queued_message(&pointerAlphaMsg);
|
||||
CopyMemory(&pointerAlphaMsg, &message, sizeof(wMessage));
|
||||
break;
|
||||
|
||||
case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
|
||||
/* Abandon previous message */
|
||||
shadow_client_free_queued_message(&audioVolumeMsg);
|
||||
CopyMemory(&audioVolumeMsg, &message, sizeof(wMessage));
|
||||
break;
|
||||
|
||||
default:
|
||||
shadow_client_subsystem_process_message(client, &message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (message.id == WMQ_QUIT)
|
||||
{
|
||||
/* Release stored message */
|
||||
shadow_client_free_queued_message(&pointerPositionMsg);
|
||||
shadow_client_free_queued_message(&pointerAlphaMsg);
|
||||
shadow_client_free_queued_message(&audioVolumeMsg);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Process accumulated messages if needed */
|
||||
if (pointerPositionMsg.id)
|
||||
{
|
||||
shadow_client_subsystem_process_message(client, &pointerPositionMsg);
|
||||
}
|
||||
if (pointerAlphaMsg.id)
|
||||
{
|
||||
shadow_client_subsystem_process_message(client, &pointerAlphaMsg);
|
||||
}
|
||||
if (audioVolumeMsg.id)
|
||||
{
|
||||
shadow_client_subsystem_process_message(client, &audioVolumeMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Free channels early because we establish channels in post connect */
|
||||
shadow_client_channels_free(client);
|
||||
|
||||
if (UpdateSubscriber)
|
||||
{
|
||||
shadow_multiclient_release_subscriber(UpdateSubscriber);
|
||||
@ -1119,3 +1212,102 @@ BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void shadow_msg_out_addref(wMessage* message)
|
||||
{
|
||||
SHADOW_MSG_OUT* msg = (SHADOW_MSG_OUT *)message->wParam;
|
||||
InterlockedIncrement(&(msg->refCount));
|
||||
}
|
||||
|
||||
static void shadow_msg_out_release(wMessage* message)
|
||||
{
|
||||
SHADOW_MSG_OUT* msg = (SHADOW_MSG_OUT *)message->wParam;
|
||||
if (InterlockedDecrement(&(msg->refCount)) <= 0)
|
||||
{
|
||||
if (msg->Free)
|
||||
msg->Free(message->id, msg);
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL shadow_client_dispatch_msg(rdpShadowClient* client, wMessage* message)
|
||||
{
|
||||
/* Add reference when it is posted */
|
||||
shadow_msg_out_addref(message);
|
||||
if (MessageQueue_Dispatch(client->MsgQueue, message))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Release the reference since post failed */
|
||||
shadow_msg_out_release(message);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL shadow_client_post_msg(rdpShadowClient* client, void* context, UINT32 type, SHADOW_MSG_OUT* msg, void* lParam)
|
||||
{
|
||||
wMessage message = {0};
|
||||
|
||||
message.context = context;
|
||||
message.id = type;
|
||||
message.wParam = (void *)msg;
|
||||
message.lParam = lParam;
|
||||
message.Free = shadow_msg_out_release;
|
||||
|
||||
return shadow_client_dispatch_msg(client, &message);
|
||||
}
|
||||
|
||||
int shadow_client_boardcast_msg(rdpShadowServer* server, void* context, UINT32 type, SHADOW_MSG_OUT* msg, void* lParam)
|
||||
{
|
||||
wMessage message = {0};
|
||||
rdpShadowClient* client = NULL;
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
|
||||
message.context = context;
|
||||
message.id = type;
|
||||
message.wParam = (void *)msg;
|
||||
message.lParam = lParam;
|
||||
message.Free = shadow_msg_out_release;
|
||||
|
||||
/* First add reference as we reference it in this function.
|
||||
* Therefore it would not be free'ed during post. */
|
||||
shadow_msg_out_addref(&message);
|
||||
|
||||
ArrayList_Lock(server->clients);
|
||||
for (index = 0; index < ArrayList_Count(server->clients); index++)
|
||||
{
|
||||
client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
|
||||
if (shadow_client_dispatch_msg(client, &message))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
ArrayList_Unlock(server->clients);
|
||||
|
||||
/* Release the reference for this function */
|
||||
shadow_msg_out_release(&message);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int shadow_client_boardcast_quit(rdpShadowServer* server, int nExitCode)
|
||||
{
|
||||
wMessageQueue* queue = NULL;
|
||||
int count = 0;
|
||||
int index = 0;
|
||||
|
||||
ArrayList_Lock(server->clients);
|
||||
for (index = 0; index < ArrayList_Count(server->clients); index++)
|
||||
{
|
||||
queue = ((rdpShadowClient*)ArrayList_GetItem(server->clients, index))->MsgQueue;
|
||||
if (MessageQueue_PostQuit(queue, nExitCode))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
ArrayList_Unlock(server->clients);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -113,6 +113,7 @@ void shadow_client_encomsp_uninit(rdpShadowClient* client)
|
||||
{
|
||||
if (client->encomsp) {
|
||||
client->encomsp->Stop(client->encomsp);
|
||||
encomsp_server_context_free(client->encomsp);
|
||||
client->encomsp = NULL;
|
||||
}
|
||||
}
|
||||
|
111
server/shadow/shadow_rdpsnd.c
Normal file
111
server/shadow/shadow_rdpsnd.c
Normal file
@ -0,0 +1,111 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.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 <freerdp/log.h>
|
||||
#include "shadow.h"
|
||||
|
||||
#include "shadow_rdpsnd.h"
|
||||
|
||||
#define TAG SERVER_TAG("shadow")
|
||||
|
||||
/* Default supported audio formats */
|
||||
static const AUDIO_FORMAT default_supported_audio_formats[] =
|
||||
{
|
||||
{ WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0, NULL },
|
||||
{ WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, 0, NULL }
|
||||
};
|
||||
|
||||
static void rdpsnd_activated(RdpsndServerContext* context)
|
||||
{
|
||||
AUDIO_FORMAT* agreed_format = NULL;
|
||||
int i = 0, j = 0;
|
||||
for (i = 0; i < context->num_client_formats; i++)
|
||||
{
|
||||
for (j = 0; j < context->num_server_formats; j++)
|
||||
{
|
||||
if ((context->client_formats[i].wFormatTag == context->server_formats[j].wFormatTag) &&
|
||||
(context->client_formats[i].nChannels == context->server_formats[j].nChannels) &&
|
||||
(context->client_formats[i].nSamplesPerSec == context->server_formats[j].nSamplesPerSec))
|
||||
{
|
||||
agreed_format = (AUDIO_FORMAT*) &context->server_formats[j];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (agreed_format != NULL)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (agreed_format == NULL)
|
||||
{
|
||||
WLog_ERR(TAG, "Could not agree on a audio format with the server\n");
|
||||
return;
|
||||
}
|
||||
|
||||
context->SelectFormat(context, i);
|
||||
context->SetVolume(context, 0x7FFF, 0x7FFF);
|
||||
}
|
||||
|
||||
int shadow_client_rdpsnd_init(rdpShadowClient* client)
|
||||
{
|
||||
RdpsndServerContext* rdpsnd;
|
||||
|
||||
rdpsnd = client->rdpsnd = rdpsnd_server_context_new(client->vcm);
|
||||
if (!rdpsnd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
rdpsnd->data = client;
|
||||
|
||||
if (client->subsystem->rdpsndFormats)
|
||||
{
|
||||
rdpsnd->server_formats = client->subsystem->rdpsndFormats;
|
||||
rdpsnd->num_server_formats = client->subsystem->nRdpsndFormats;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set default audio formats. */
|
||||
rdpsnd->server_formats = default_supported_audio_formats;
|
||||
rdpsnd->num_server_formats =
|
||||
sizeof(default_supported_audio_formats) / sizeof(default_supported_audio_formats[0]);
|
||||
}
|
||||
|
||||
rdpsnd->src_format = rdpsnd->server_formats[0];
|
||||
|
||||
rdpsnd->Activated = rdpsnd_activated;
|
||||
|
||||
rdpsnd->Initialize(rdpsnd, TRUE);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
void shadow_client_rdpsnd_uninit(rdpShadowClient* client)
|
||||
{
|
||||
if (client->rdpsnd)
|
||||
{
|
||||
client->rdpsnd->Stop(client->rdpsnd);
|
||||
rdpsnd_server_context_free(client->rdpsnd);
|
||||
client->rdpsnd = NULL;
|
||||
}
|
||||
}
|
38
server/shadow/shadow_rdpsnd.h
Normal file
38
server/shadow/shadow_rdpsnd.h
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.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 FREERDP_SHADOW_SERVER_RDPSND_H
|
||||
#define FREERDP_SHADOW_SERVER_RDPSND_H
|
||||
|
||||
#include <freerdp/server/shadow.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int shadow_client_rdpsnd_init(rdpShadowClient* client);
|
||||
void shadow_client_rdpsnd_uninit(rdpShadowClient* client);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_SHADOW_SERVER_RDPSND_H */
|
@ -42,6 +42,7 @@ void shadow_client_remdesk_uninit(rdpShadowClient* client)
|
||||
{
|
||||
if (client->remdesk) {
|
||||
client->remdesk->Stop(client->remdesk);
|
||||
remdesk_server_context_free(client->remdesk);
|
||||
client->remdesk = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -346,7 +346,7 @@ void* shadow_server_thread(rdpShadowServer* server)
|
||||
|
||||
/* Signal to the clients that server is being stopped and wait for them
|
||||
* to disconnect. */
|
||||
if (MessageQueue_PostQuit(subsystem->MsgPipe->Out, 0))
|
||||
if (shadow_client_boardcast_quit(server, 0))
|
||||
{
|
||||
while(ArrayList_Count(server->clients) > 0)
|
||||
{
|
||||
|
@ -107,6 +107,16 @@ fail:
|
||||
return status;
|
||||
}
|
||||
|
||||
static void shadow_subsystem_free_queued_message(void *obj)
|
||||
{
|
||||
wMessage *message = (wMessage*)obj;
|
||||
if (message->Free)
|
||||
{
|
||||
message->Free(message);
|
||||
message->Free = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem)
|
||||
{
|
||||
if (!subsystem)
|
||||
@ -117,6 +127,11 @@ void shadow_subsystem_uninit(rdpShadowSubsystem* subsystem)
|
||||
|
||||
if (subsystem->MsgPipe)
|
||||
{
|
||||
/* Release resource in messages before free */
|
||||
subsystem->MsgPipe->In->object.fnObjectFree = shadow_subsystem_free_queued_message;
|
||||
MessageQueue_Clear(subsystem->MsgPipe->In);
|
||||
subsystem->MsgPipe->Out->object.fnObjectFree = shadow_subsystem_free_queued_message;
|
||||
MessageQueue_Clear(subsystem->MsgPipe->Out);
|
||||
MessagePipe_Free(subsystem->MsgPipe);
|
||||
subsystem->MsgPipe = NULL;
|
||||
}
|
||||
|
@ -24,45 +24,6 @@
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
|
||||
#define SHADOW_MSG_IN_REFRESH_OUTPUT_ID 1001
|
||||
#define SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID 1002
|
||||
|
||||
struct _SHADOW_MSG_IN_REFRESH_OUTPUT
|
||||
{
|
||||
UINT32 numRects;
|
||||
RECTANGLE_16* rects;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_IN_REFRESH_OUTPUT SHADOW_MSG_IN_REFRESH_OUTPUT;
|
||||
|
||||
struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT
|
||||
{
|
||||
BOOL allow;
|
||||
RECTANGLE_16 rect;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT;
|
||||
|
||||
#define SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID 2001
|
||||
#define SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID 2002
|
||||
|
||||
struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE
|
||||
{
|
||||
UINT32 xPos;
|
||||
UINT32 yPos;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE SHADOW_MSG_OUT_POINTER_POSITION_UPDATE;
|
||||
|
||||
struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE
|
||||
{
|
||||
UINT32 xHot;
|
||||
UINT32 yHot;
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
BYTE* pixels;
|
||||
int scanline;
|
||||
BOOL premultiplied;
|
||||
};
|
||||
typedef struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user