From 8485d866d4a466cc9a882468ee7a9fa92fde2ef2 Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Thu, 9 Apr 2015 02:13:52 +0800 Subject: [PATCH 1/2] 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. --- include/freerdp/server/shadow.h | 91 +++++++++++- server/shadow/CMakeLists.txt | 4 + server/shadow/X11/x11_shadow.c | 21 ++- server/shadow/shadow_audin.c | 121 ++++++++++++++++ server/shadow/shadow_audin.h | 38 +++++ server/shadow/shadow_channels.c | 18 +++ server/shadow/shadow_channels.h | 3 + server/shadow/shadow_client.c | 233 +++++++++++++++++++++++++++---- server/shadow/shadow_encomsp.c | 1 + server/shadow/shadow_rdpsnd.c | 111 +++++++++++++++ server/shadow/shadow_rdpsnd.h | 38 +++++ server/shadow/shadow_remdesk.c | 1 + server/shadow/shadow_server.c | 2 +- server/shadow/shadow_subsystem.c | 15 ++ server/shadow/shadow_subsystem.h | 39 ------ 15 files changed, 662 insertions(+), 74 deletions(-) create mode 100644 server/shadow/shadow_audin.c create mode 100644 server/shadow/shadow_audin.h create mode 100644 server/shadow/shadow_rdpsnd.c create mode 100644 server/shadow/shadow_rdpsnd.h diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index eb8233a04..b77f054e3 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -31,6 +31,8 @@ #include #include +#include +#include #include #include @@ -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 diff --git a/server/shadow/CMakeLists.txt b/server/shadow/CMakeLists.txt index 06c60f5d1..eda2f617d 100644 --- a/server/shadow/CMakeLists.txt +++ b/server/shadow/CMakeLists.txt @@ -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 diff --git a/server/shadow/X11/x11_shadow.c b/server/shadow/X11/x11_shadow.c index 70fc36ab6..9d67793d5 100644 --- a/server/shadow/X11/x11_shadow.c +++ b/server/shadow/X11/x11_shadow.c @@ -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) diff --git a/server/shadow/shadow_audin.c b/server/shadow/shadow_audin.c new file mode 100644 index 000000000..0b975b39b --- /dev/null +++ b/server/shadow/shadow_audin.c @@ -0,0 +1,121 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2015 Jiang Zihao + * + * 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 +#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; + } +} diff --git a/server/shadow/shadow_audin.h b/server/shadow/shadow_audin.h new file mode 100644 index 000000000..a02bd3b4e --- /dev/null +++ b/server/shadow/shadow_audin.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2015 Jiang Zihao + * + * 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 + +#include +#include + +#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 */ diff --git a/server/shadow/shadow_channels.c b/server/shadow/shadow_channels.c index 5a2e4bb03..eaf787e34 100644 --- a/server/shadow/shadow_channels.c +++ b/server/shadow/shadow_channels.c @@ -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); +} diff --git a/server/shadow/shadow_channels.h b/server/shadow/shadow_channels.h index 7c11eb84e..d6abef9c7 100644 --- a/server/shadow/shadow_channels.h +++ b/server/shadow/shadow_channels.h @@ -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 } diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index e332688d9..4ed644691 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -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; +} diff --git a/server/shadow/shadow_encomsp.c b/server/shadow/shadow_encomsp.c index 61bb2e582..2540eaf5d 100644 --- a/server/shadow/shadow_encomsp.c +++ b/server/shadow/shadow_encomsp.c @@ -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; } } diff --git a/server/shadow/shadow_rdpsnd.c b/server/shadow/shadow_rdpsnd.c new file mode 100644 index 000000000..15428c655 --- /dev/null +++ b/server/shadow/shadow_rdpsnd.c @@ -0,0 +1,111 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2015 Jiang Zihao + * + * 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 +#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; + } +} diff --git a/server/shadow/shadow_rdpsnd.h b/server/shadow/shadow_rdpsnd.h new file mode 100644 index 000000000..b95e9ce3b --- /dev/null +++ b/server/shadow/shadow_rdpsnd.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2015 Jiang Zihao + * + * 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 + +#include +#include + +#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 */ diff --git a/server/shadow/shadow_remdesk.c b/server/shadow/shadow_remdesk.c index 5e7b27330..0797a25ac 100644 --- a/server/shadow/shadow_remdesk.c +++ b/server/shadow/shadow_remdesk.c @@ -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; } } diff --git a/server/shadow/shadow_server.c b/server/shadow/shadow_server.c index 6a985fb04..36f81fdfd 100644 --- a/server/shadow/shadow_server.c +++ b/server/shadow/shadow_server.c @@ -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) { diff --git a/server/shadow/shadow_subsystem.c b/server/shadow/shadow_subsystem.c index 5316e45fc..665a1ebf8 100644 --- a/server/shadow/shadow_subsystem.c +++ b/server/shadow/shadow_subsystem.c @@ -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; } diff --git a/server/shadow/shadow_subsystem.h b/server/shadow/shadow_subsystem.h index 9ad710475..07031589d 100644 --- a/server/shadow/shadow_subsystem.h +++ b/server/shadow/shadow_subsystem.h @@ -24,45 +24,6 @@ #include #include -#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 From 15707363fb83029f873892d0468b10d2b0d75c1b Mon Sep 17 00:00:00 2001 From: "zihao.jiang" Date: Mon, 15 Jun 2015 23:54:30 +0800 Subject: [PATCH 2/2] server/shadow: Integrate comment from @hardening: use switch to handle different message id. --- server/shadow/Mac/mac_shadow.c | 74 ++++++++------ server/shadow/X11/x11_shadow.c | 91 ++++++++++------- server/shadow/shadow_client.c | 181 ++++++++++++++++++--------------- 3 files changed, 193 insertions(+), 153 deletions(-) diff --git a/server/shadow/Mac/mac_shadow.c b/server/shadow/Mac/mac_shadow.c index f4e25c984..d3fbb77b0 100644 --- a/server/shadow/Mac/mac_shadow.c +++ b/server/shadow/Mac/mac_shadow.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; } diff --git a/server/shadow/X11/x11_shadow.c b/server/shadow/X11/x11_shadow.c index 9d67793d5..c297683a8 100644 --- a/server/shadow/X11/x11_shadow.c +++ b/server/shadow/X11/x11_shadow.c @@ -350,14 +350,21 @@ void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16 static void x11_shadow_message_free(UINT32 id, SHADOW_MSG_OUT* msg) { - if (id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID) + switch(id) { - free(msg); - } - else if (id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID) - { - free(((SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)msg)->pixels); - free(msg); + 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; } } @@ -743,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) diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 4ed644691..17c36fa03 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -165,17 +165,21 @@ void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* 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; } } @@ -894,73 +898,83 @@ 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; } - } - 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; } - } - 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) + case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID: { - client->rdpsnd->src_format = msg->audio_format; - IFCALL(client->rdpsnd->SendSamples, client->rdpsnd, msg->buf, msg->nFrames, msg->wTimestamp); + 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; } - } - 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) + case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID: { - IFCALL(client->rdpsnd->SetVolume, client->rdpsnd, msg->left, msg->right); + 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); @@ -1090,27 +1104,30 @@ void* shadow_client_thread(rdpShadowClient* client) { break; } - else if (message.id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID) + + switch(message.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); + 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; } }