This is originally to add audio support. Several fixes included:

1. Introduce message queue in shadow client. No longer use subsytem->MsgPipe->out to deliver message to clients.
We used to use subsytem->MsgPipe->out for messages which need to be sent to client. But it's not correct. Only one client would get the message if multiple client exists
This problem make the fix in PR #2643 incomplete.
Introduced reference count based solution to release resource taken by the message.
Also added APIs for client message delivery.
Also fixed msg pipe in subsystem to clean resource when destroyed.
2. Discard unused StopEvent in client. We actually use quit message instead.
3. Enhance disposal of channels.
Free context for remdesk and encomsp channels. The original fix only stop the threads, but doesn't release resource.
Dispose channels earlier. The channels are built on client->vcm. Disposing channels after client->vcm is closed cause unknown behavior.
Original fix is #2644
4. Start to add audio support.
This commit is contained in:
zihao.jiang 2015-04-09 02:13:52 +08:00
parent 0278f7f4ba
commit 8485d866d4
15 changed files with 662 additions and 74 deletions

View File

@ -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>
@ -71,6 +73,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;
@ -80,7 +84,7 @@ struct rdp_shadow_client
BOOL inLobby;
BOOL mayView;
BOOL mayInteract;
HANDLE StopEvent;
wMessageQueue* MsgQueue;
CRITICAL_SECTION lock;
REGION16 invalidRegion;
rdpShadowServer* server;
@ -94,6 +98,8 @@ struct rdp_shadow_client
HANDLE vcm;
EncomspServerContext* encomsp;
RemdeskServerContext* remdesk;
RdpsndServerContext* rdpsnd;
audin_server_context* audin;
};
struct rdp_shadow_server
@ -151,11 +157,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; \
\
@ -166,6 +178,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
@ -184,6 +269,10 @@ FREERDP_API int shadow_enum_monitors(MONITOR_DEF* monitors, int maxMonitors, con
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

View File

@ -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

View File

@ -348,11 +348,23 @@ void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16
#endif
}
static void x11_shadow_message_free(UINT32 id, SHADOW_MSG_OUT* msg)
{
if (id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID)
{
free(msg);
}
else if (id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID)
{
free(((SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)msg)->pixels);
free(msg);
}
}
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 +373,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 +404,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)

View 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;
}
}

View 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 */

View File

@ -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);
}

View File

@ -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
}

View File

@ -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,10 +161,6 @@ 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)
@ -902,8 +912,6 @@ int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* m
client->pointerY = msg->yPos;
}
}
free(msg);
}
else if (message->id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID)
{
@ -936,10 +944,26 @@ int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* m
free(pointerColor->xorMaskData);
free(pointerColor->andMaskData);
}
free(msg->pixels);
free(msg);
}
else if (message->id == 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);
}
}
else if (message->id == 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);
}
}
shadow_client_free_queued_message(message);
return 1;
}
@ -949,8 +973,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;
@ -962,7 +988,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;
@ -985,14 +1011,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);
@ -1000,19 +1025,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)
@ -1056,18 +1075,75 @@ 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;
}
else if (message.id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID)
{
/* Abandon previous message */
shadow_client_free_queued_message(&pointerPositionMsg);
CopyMemory(&pointerPositionMsg, &message, sizeof(wMessage));
}
else if (message.id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID)
{
/* Abandon previous message */
shadow_client_free_queued_message(&pointerAlphaMsg);
CopyMemory(&pointerAlphaMsg, &message, sizeof(wMessage));
}
else if (message.id == SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID)
{
/* Abandon previous message */
shadow_client_free_queued_message(&audioVolumeMsg);
CopyMemory(&audioVolumeMsg, &message, sizeof(wMessage));
}
else
{
shadow_client_subsystem_process_message(client, &message);
}
}
shadow_client_subsystem_process_message(client, &message);
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);
@ -1109,3 +1185,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;
}

View File

@ -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;
}
}

View 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;
}
}

View 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 */

View File

@ -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;
}
}

View File

@ -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)
{

View File

@ -167,6 +167,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)
@ -177,6 +187,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;
}

View File

@ -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