2 * FreeRDP: A Remote Desktop Protocol Implementation
4 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
23 #include <winpr/crt.h>
24 #include <winpr/file.h>
25 #include <winpr/path.h>
26 #include <winpr/synch.h>
27 #include <winpr/thread.h>
28 #include <winpr/sysinfo.h>
29 #include <winpr/interlocked.h>
31 #include <freerdp/log.h>
35 #define TAG CLIENT_TAG("shadow")
37 static void shadow_client_free_queued_message(void *obj)
39 wMessage *message = (wMessage*)obj;
42 message->Free(message);
47 BOOL shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
49 rdpSettings* settings;
50 rdpShadowServer* server;
51 const wObject cb = { NULL, NULL, NULL, shadow_client_free_queued_message, NULL };
53 server = (rdpShadowServer*) peer->ContextExtra;
54 client->server = server;
55 client->subsystem = server->subsystem;
57 settings = peer->settings;
59 settings->ColorDepth = 32;
60 settings->NSCodec = TRUE;
61 settings->RemoteFxCodec = TRUE;
62 settings->BitmapCacheV3Enabled = TRUE;
63 settings->FrameMarkerCommandEnabled = TRUE;
64 settings->SurfaceFrameMarkerEnabled = TRUE;
65 settings->SupportGraphicsPipeline = FALSE;
67 settings->DrawAllowSkipAlpha = TRUE;
68 settings->DrawAllowColorSubsampling = TRUE;
69 settings->DrawAllowDynamicColorFidelity = TRUE;
71 settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
73 settings->RdpSecurity = TRUE;
74 settings->TlsSecurity = TRUE;
75 settings->NlaSecurity = FALSE;
77 if (!(settings->CertificateFile = _strdup(server->CertificateFile)))
79 if (!(settings->PrivateKeyFile = _strdup(server->PrivateKeyFile)))
80 goto fail_privkey_file;
81 if (!(settings->RdpKeyFile = _strdup(settings->PrivateKeyFile)))
82 goto fail_rdpkey_file;
85 if (server->ipcSocket)
87 settings->LyncRdpMode = TRUE;
88 settings->CompressionEnabled = FALSE;
91 client->inLobby = TRUE;
92 client->mayView = server->mayView;
93 client->mayInteract = server->mayInteract;
95 if (!InitializeCriticalSectionAndSpinCount(&(client->lock), 4000))
96 goto fail_client_lock;
98 region16_init(&(client->invalidRegion));
100 client->vcm = WTSOpenServerA((LPSTR) peer->context);
101 if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
102 goto fail_open_server;
104 if (!(client->MsgQueue = MessageQueue_New(&cb)))
105 goto fail_message_queue;
107 if (!(client->encoder = shadow_encoder_new(client)))
108 goto fail_encoder_new;
110 if (ArrayList_Add(server->clients, (void*) client) >= 0)
113 shadow_encoder_free(client->encoder);
114 client->encoder = NULL;
116 MessageQueue_Free(client->MsgQueue);
117 client->MsgQueue = NULL;
119 WTSCloseServer((HANDLE) client->vcm);
122 DeleteCriticalSection(&(client->lock));
124 free(settings->RdpKeyFile);
125 settings->RdpKeyFile = NULL;
127 free(settings->PrivateKeyFile);
128 settings->PrivateKeyFile = NULL;
130 free(settings->CertificateFile);
131 settings->CertificateFile = NULL;
137 void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
139 rdpShadowServer* server = client->server;
141 ArrayList_Remove(server->clients, (void*) client);
143 DeleteCriticalSection(&(client->lock));
145 region16_uninit(&(client->invalidRegion));
147 WTSCloseServer((HANDLE) client->vcm);
149 /* Clear queued messages and free resource */
150 MessageQueue_Clear(client->MsgQueue);
151 MessageQueue_Free(client->MsgQueue);
155 shadow_surface_free(client->lobby);
156 client->lobby = NULL;
161 shadow_encoder_free(client->encoder);
162 client->encoder = NULL;
166 void shadow_client_message_free(wMessage* message)
170 case SHADOW_MSG_IN_REFRESH_OUTPUT_ID:
171 free(((SHADOW_MSG_IN_REFRESH_OUTPUT*)message->wParam)->rects);
172 free(message->wParam);
175 case SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID:
176 free(message->wParam);
180 WLog_ERR(TAG, "Unknown message id: %u", message->id);
181 free(message->wParam);
186 BOOL shadow_client_capabilities(freerdp_peer* peer)
191 BOOL shadow_client_post_connect(freerdp_peer* peer)
195 rdpSettings* settings;
196 rdpShadowClient* client;
197 rdpShadowServer* server;
198 RECTANGLE_16 invalidRect;
199 rdpShadowSubsystem* subsystem;
201 client = (rdpShadowClient*) peer->context;
202 settings = peer->settings;
203 server = client->server;
204 subsystem = server->subsystem;
206 if (!server->shareSubRect)
208 width = server->screen->width;
209 height = server->screen->height;
213 width = server->subRect.right - server->subRect.left;
214 height = server->subRect.bottom - server->subRect.top;
217 settings->DesktopWidth = width;
218 settings->DesktopHeight = height;
220 if (settings->ColorDepth == 24)
221 settings->ColorDepth = 16; /* disable 24bpp */
223 if (settings->MultifragMaxRequestSize < 0x3F0000)
224 settings->NSCodec = FALSE; /* NSCodec compressor does not support fragmentation yet */
226 WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)",
227 peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth);
229 peer->update->DesktopResize(peer->update->context);
231 shadow_client_channels_post_connect(client);
233 invalidRect.left = 0;
235 invalidRect.right = width;
236 invalidRect.bottom = height;
238 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect);
240 shadow_client_init_lobby(client);
244 if (settings->Username && settings->Password)
245 settings->AutoLogonEnabled = TRUE;
247 if (settings->AutoLogonEnabled && server->authentication)
249 if (subsystem->Authenticate)
251 authStatus = subsystem->Authenticate(subsystem,
252 settings->Username, settings->Domain, settings->Password);
256 if (server->authentication)
260 WLog_ERR(TAG, "client authentication failure: %d", authStatus);
268 BOOL shadow_client_refresh_rect(rdpShadowClient* client, BYTE count, RECTANGLE_16* areas)
270 wMessage message = { 0 };
271 SHADOW_MSG_IN_REFRESH_OUTPUT* wParam;
272 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
277 if (!(wParam = (SHADOW_MSG_IN_REFRESH_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_REFRESH_OUTPUT))))
280 wParam->numRects = (UINT32) count;
282 if (wParam->numRects)
284 wParam->rects = (RECTANGLE_16*) calloc(wParam->numRects, sizeof(RECTANGLE_16));
292 CopyMemory(wParam->rects, areas, wParam->numRects * sizeof(RECTANGLE_16));
295 message.id = SHADOW_MSG_IN_REFRESH_OUTPUT_ID;
296 message.wParam = (void*) wParam;
297 message.lParam = NULL;
298 message.context = (void*) client;
299 message.Free = shadow_client_message_free;
301 return MessageQueue_Dispatch(MsgPipe->In, &message);
304 BOOL shadow_client_suppress_output(rdpShadowClient* client, BYTE allow, RECTANGLE_16* area)
306 wMessage message = { 0 };
307 SHADOW_MSG_IN_SUPPRESS_OUTPUT* wParam;
308 wMessagePipe* MsgPipe = client->subsystem->MsgPipe;
310 wParam = (SHADOW_MSG_IN_SUPPRESS_OUTPUT*) calloc(1, sizeof(SHADOW_MSG_IN_SUPPRESS_OUTPUT));
314 wParam->allow = (UINT32) allow;
317 CopyMemory(&(wParam->rect), area, sizeof(RECTANGLE_16));
319 message.id = SHADOW_MSG_IN_SUPPRESS_OUTPUT_ID;
320 message.wParam = (void*) wParam;
321 message.lParam = NULL;
322 message.context = (void*) client;
323 message.Free = shadow_client_message_free;
325 return MessageQueue_Dispatch(MsgPipe->In, &message);
328 BOOL shadow_client_activate(freerdp_peer* peer)
330 rdpSettings* settings = peer->settings;
331 rdpShadowClient* client = (rdpShadowClient*) peer->context;
333 if (settings->ClientDir && (strcmp(settings->ClientDir, "librdp") == 0))
335 /* Hack for Mac/iOS/Android Microsoft RDP clients */
337 settings->RemoteFxCodec = FALSE;
339 settings->NSCodec = FALSE;
340 settings->NSCodecAllowSubsampling = FALSE;
342 settings->SurfaceFrameMarkerEnabled = FALSE;
345 client->activated = TRUE;
346 client->inLobby = client->mayView ? FALSE : TRUE;
348 shadow_encoder_reset(client->encoder);
350 return shadow_client_refresh_rect(client, 0, NULL);
353 BOOL shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
355 SURFACE_FRAME* frame;
356 wListDictionary* frameList;
358 frameList = client->encoder->frameList;
359 frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(frameList, (void*) (size_t) frameId);
363 ListDictionary_Remove(frameList, (void*) (size_t) frameId);
369 int shadow_client_send_surface_frame_marker(rdpShadowClient* client, UINT32 action, UINT32 id)
371 SURFACE_FRAME_MARKER surfaceFrameMarker;
372 rdpContext* context = (rdpContext*) client;
373 rdpUpdate* update = context->update;
375 surfaceFrameMarker.frameAction = action;
376 surfaceFrameMarker.frameId = id;
378 IFCALL(update->SurfaceFrameMarker, context, &surfaceFrameMarker);
383 int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
395 rdpSettings* settings;
396 rdpShadowServer* server;
397 rdpShadowEncoder* encoder;
398 SURFACE_BITS_COMMAND cmd;
400 context = (rdpContext*) client;
401 update = context->update;
402 settings = context->settings;
404 server = client->server;
405 encoder = client->encoder;
407 pSrcData = surface->data;
408 nSrcStep = surface->scanline;
410 if (server->shareSubRect)
413 int subWidth, subHeight;
415 subX = server->subRect.left;
416 subY = server->subRect.top;
417 subWidth = server->subRect.right - server->subRect.left;
418 subHeight = server->subRect.bottom - server->subRect.top;
422 pSrcData = &pSrcData[(subY * nSrcStep) + (subX * 4)];
425 if (encoder->frameAck)
426 frameId = (UINT32) shadow_encoder_create_frame_id(encoder);
428 if (settings->RemoteFxCodec)
431 RFX_MESSAGE* messages;
432 RFX_RECT *messageRects = NULL;
434 shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX);
441 rect.height = nHeight;
443 if (!(messages = rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
444 surface->width, surface->height, nSrcStep, &numMessages,
445 settings->MultifragMaxRequestSize)))
450 cmd.codecID = settings->RemoteFxCodecId;
454 cmd.destRight = surface->width;
455 cmd.destBottom = surface->height;
458 cmd.width = surface->width;
459 cmd.height = surface->height;
460 cmd.skipCompression = TRUE;
463 messageRects = messages[0].rects;
465 for (i = 0; i < numMessages; i++)
467 Stream_SetPosition(s, 0);
468 if (!rfx_write_message(encoder->rfx, s, &messages[i]))
470 while (i < numMessages)
472 rfx_message_free(encoder->rfx, &messages[i++]);
476 rfx_message_free(encoder->rfx, &messages[i]);
478 cmd.bitmapDataLength = Stream_GetPosition(s);
479 cmd.bitmapData = Stream_Buffer(s);
481 first = (i == 0) ? TRUE : FALSE;
482 last = ((i + 1) == numMessages) ? TRUE : FALSE;
484 if (!encoder->frameAck)
485 IFCALL(update->SurfaceBits, update->context, &cmd);
487 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
493 else if (settings->NSCodec)
495 shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC);
498 Stream_SetPosition(s, 0);
500 pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
502 nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep);
505 cmd.codecID = settings->NSCodecId;
506 cmd.destLeft = nXSrc;
508 cmd.destRight = cmd.destLeft + nWidth;
509 cmd.destBottom = cmd.destTop + nHeight;
511 cmd.height = nHeight;
513 cmd.bitmapDataLength = Stream_GetPosition(s);
514 cmd.bitmapData = Stream_Buffer(s);
519 if (!encoder->frameAck)
520 IFCALL(update->SurfaceBits, update->context, &cmd);
522 IFCALL(update->SurfaceFrameBits, update->context, &cmd, first, last, frameId);
528 int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* surface, int nXSrc, int nYSrc, int nWidth, int nHeight)
541 rdpSettings* settings;
542 UINT32 maxUpdateSize;
543 UINT32 totalBitmapSize;
544 UINT32 updateSizeEstimate;
545 BITMAP_DATA* bitmapData;
546 BITMAP_UPDATE bitmapUpdate;
547 rdpShadowServer* server;
548 rdpShadowEncoder* encoder;
550 context = (rdpContext*) client;
551 update = context->update;
552 settings = context->settings;
554 server = client->server;
555 encoder = client->encoder;
557 maxUpdateSize = settings->MultifragMaxRequestSize;
559 if (settings->ColorDepth < 32)
560 shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED);
562 shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR);
564 pSrcData = surface->data;
565 nSrcStep = surface->scanline;
566 SrcFormat = PIXEL_FORMAT_RGB32;
568 if ((nXSrc % 4) != 0)
570 nWidth += (nXSrc % 4);
571 nXSrc -= (nXSrc % 4);
574 if ((nYSrc % 4) != 0)
576 nHeight += (nYSrc % 4);
577 nYSrc -= (nYSrc % 4);
580 rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
581 cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
586 bitmapUpdate.count = bitmapUpdate.number = rows * cols;
587 bitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * bitmapUpdate.number);
588 bitmapUpdate.rectangles = bitmapData;
593 if ((nWidth % 4) != 0)
595 nXSrc -= (nWidth % 4);
596 nWidth += (nWidth % 4);
599 if ((nHeight % 4) != 0)
601 nYSrc -= (nHeight % 4);
602 nHeight += (nHeight % 4);
605 for (yIdx = 0; yIdx < rows; yIdx++)
607 for (xIdx = 0; xIdx < cols; xIdx++)
609 bitmap = &bitmapData[k];
613 bitmap->destLeft = nXSrc + (xIdx * 64);
614 bitmap->destTop = nYSrc + (yIdx * 64);
616 if ((bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
617 bitmap->width = (nXSrc + nWidth) - bitmap->destLeft;
619 if ((bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
620 bitmap->height = (nYSrc + nHeight) - bitmap->destTop;
622 bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
623 bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
624 bitmap->compressed = TRUE;
626 if ((bitmap->width < 4) || (bitmap->height < 4))
629 if (settings->ColorDepth < 32)
631 int bitsPerPixel = settings->ColorDepth;
632 int bytesPerPixel = (bitsPerPixel + 7) / 8;
634 DstSize = 64 * 64 * 4;
635 buffer = encoder->grid[k];
637 interleaved_compress(encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height,
638 pSrcData, SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, NULL, bitsPerPixel);
640 bitmap->bitmapDataStream = buffer;
641 bitmap->bitmapLength = DstSize;
642 bitmap->bitsPerPixel = bitsPerPixel;
643 bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
644 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
650 buffer = encoder->grid[k];
651 data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
653 buffer = freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat,
654 bitmap->width, bitmap->height, nSrcStep, buffer, &dstSize);
656 bitmap->bitmapDataStream = buffer;
657 bitmap->bitmapLength = dstSize;
658 bitmap->bitsPerPixel = 32;
659 bitmap->cbScanWidth = bitmap->width * 4;
660 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
663 bitmap->cbCompFirstRowSize = 0;
664 bitmap->cbCompMainBodySize = bitmap->bitmapLength;
666 totalBitmapSize += bitmap->bitmapLength;
671 bitmapUpdate.count = bitmapUpdate.number = k;
673 updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.count) + 16;
675 if (updateSizeEstimate > maxUpdateSize)
679 UINT32 newUpdateSize;
680 BITMAP_DATA* fragBitmapData;
682 fragBitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * k);
683 bitmapUpdate.rectangles = fragBitmapData;
690 newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
692 if ((newUpdateSize < maxUpdateSize) && ((i + 1) < k))
694 CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
695 updateSize = newUpdateSize;
701 CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
702 updateSize = newUpdateSize;
705 bitmapUpdate.count = bitmapUpdate.number = j;
706 IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
712 free(fragBitmapData);
716 IFCALL(update->BitmapUpdate, context, &bitmapUpdate);
724 int shadow_client_send_surface_update(rdpShadowClient* client)
730 rdpSettings* settings;
731 rdpShadowServer* server;
732 rdpShadowSurface* surface;
733 rdpShadowEncoder* encoder;
734 REGION16 invalidRegion;
735 RECTANGLE_16 surfaceRect;
736 const RECTANGLE_16* extents;
738 context = (rdpContext*) client;
739 settings = context->settings;
740 server = client->server;
741 encoder = client->encoder;
743 surface = client->inLobby ? client->lobby : server->surface;
745 EnterCriticalSection(&(client->lock));
747 region16_init(&invalidRegion);
748 region16_copy(&invalidRegion, &(client->invalidRegion));
749 region16_clear(&(client->invalidRegion));
751 LeaveCriticalSection(&(client->lock));
753 surfaceRect.left = 0;
755 surfaceRect.right = surface->width;
756 surfaceRect.bottom = surface->height;
758 region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect);
760 if (server->shareSubRect)
762 region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect));
765 if (region16_is_empty(&invalidRegion))
767 region16_uninit(&invalidRegion);
771 extents = region16_extents(&invalidRegion);
773 nXSrc = extents->left - 0;
774 nYSrc = extents->top - 0;
775 nWidth = extents->right - extents->left;
776 nHeight = extents->bottom - extents->top;
778 //WLog_INFO(TAG, "shadow_client_send_surface_update: x: %d y: %d width: %d height: %d right: %d bottom: %d",
779 // nXSrc, nYSrc, nWidth, nHeight, nXSrc + nWidth, nYSrc + nHeight);
781 if (settings->RemoteFxCodec || settings->NSCodec)
783 status = shadow_client_send_surface_bits(client, surface, nXSrc, nYSrc, nWidth, nHeight);
787 status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight);
790 region16_uninit(&invalidRegion);
795 int shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
799 const RECTANGLE_16* rects;
801 EnterCriticalSection(&(client->lock));
803 rects = region16_rects(region, &numRects);
805 for (index = 0; index < numRects; index++)
807 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
810 LeaveCriticalSection(&(client->lock));
815 int shadow_client_convert_alpha_pointer_data(BYTE* pixels, BOOL premultiplied,
816 UINT32 width, UINT32 height, POINTER_COLOR_UPDATE* pointerColor)
828 xorStep = (width * 3);
829 xorStep += (xorStep % 2);
831 andStep = ((width + 7) / 8);
832 andStep += (andStep % 2);
834 pointerColor->lengthXorMask = height * xorStep;
835 pointerColor->xorMaskData = (BYTE*) calloc(1, pointerColor->lengthXorMask);
837 if (!pointerColor->xorMaskData)
840 pointerColor->lengthAndMask = height * andStep;
841 pointerColor->andMaskData = (BYTE*) calloc(1, pointerColor->lengthAndMask);
843 if (!pointerColor->andMaskData)
846 for (y = 0; y < height; y++)
848 pSrc8 = &pixels[(width * 4) * (height - 1 - y)];
849 pDst8 = &(pointerColor->xorMaskData[y * xorStep]);
852 andBits = &(pointerColor->andMaskData[andStep * y]);
854 for (x = 0; x < width; x++)
864 A = 0; /* pixel cannot be partially transparent */
868 /* transparent pixel: XOR = black, AND = 1 */
886 if (andPixel) *andBits |= andBit;
887 if (!(andBit >>= 1)) { andBits++; andBit = 0x80; }
894 int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
896 rdpContext* context = (rdpContext*) client;
897 rdpUpdate* update = context->update;
899 /* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
903 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
905 POINTER_POSITION_UPDATE pointerPosition;
906 SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) message->wParam;
908 pointerPosition.xPos = msg->xPos;
909 pointerPosition.yPos = msg->yPos;
911 if (client->activated)
913 if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
915 IFCALL(update->pointer->PointerPosition, context, &pointerPosition);
917 client->pointerX = msg->xPos;
918 client->pointerY = msg->yPos;
923 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
925 POINTER_NEW_UPDATE pointerNew;
926 POINTER_COLOR_UPDATE* pointerColor;
927 POINTER_CACHED_UPDATE pointerCached;
928 SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) message->wParam;
930 ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE));
932 pointerNew.xorBpp = 24;
933 pointerColor = &(pointerNew.colorPtrAttr);
935 pointerColor->cacheIndex = 0;
936 pointerColor->xPos = msg->xHot;
937 pointerColor->yPos = msg->yHot;
938 pointerColor->width = msg->width;
939 pointerColor->height = msg->height;
941 pointerCached.cacheIndex = pointerColor->cacheIndex;
943 if (client->activated)
945 shadow_client_convert_alpha_pointer_data(msg->pixels, msg->premultiplied,
946 msg->width, msg->height, pointerColor);
948 IFCALL(update->pointer->PointerNew, context, &pointerNew);
949 IFCALL(update->pointer->PointerCached, context, &pointerCached);
951 free(pointerColor->xorMaskData);
952 free(pointerColor->andMaskData);
956 case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
958 SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES* msg = (SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES*) message->wParam;
959 if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
961 client->rdpsnd->src_format = msg->audio_format;
962 IFCALL(client->rdpsnd->SendSamples, client->rdpsnd, msg->buf, msg->nFrames, msg->wTimestamp);
966 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
968 SHADOW_MSG_OUT_AUDIO_OUT_VOLUME* msg = (SHADOW_MSG_OUT_AUDIO_OUT_VOLUME*) message->wParam;
969 if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
971 IFCALL(client->rdpsnd->SetVolume, client->rdpsnd, msg->left, msg->right);
976 WLog_ERR(TAG, "Unknown message id: %u", message->id);
980 shadow_client_free_queued_message(message);
985 void* shadow_client_thread(rdpShadowClient* client)
990 wMessage pointerPositionMsg;
991 wMessage pointerAlphaMsg;
992 wMessage audioVolumeMsg;
996 void* UpdateSubscriber;
1000 rdpSettings* settings;
1001 rdpShadowServer* server;
1002 rdpShadowScreen* screen;
1003 rdpShadowEncoder* encoder;
1004 rdpShadowSubsystem* subsystem;
1005 wMessageQueue* MsgQueue = client->MsgQueue;
1007 server = client->server;
1008 screen = server->screen;
1009 encoder = client->encoder;
1010 subsystem = server->subsystem;
1012 context = (rdpContext*) client;
1013 peer = context->peer;
1014 settings = peer->settings;
1016 peer->Capabilities = shadow_client_capabilities;
1017 peer->PostConnect = shadow_client_post_connect;
1018 peer->Activate = shadow_client_activate;
1020 shadow_input_register_callbacks(peer->input);
1022 peer->Initialize(peer);
1024 peer->update->RefreshRect = (pRefreshRect)shadow_client_refresh_rect;
1025 peer->update->SuppressOutput = (pSuppressOutput)shadow_client_suppress_output;
1026 peer->update->SurfaceFrameAcknowledge = (pSurfaceFrameAcknowledge)shadow_client_surface_frame_acknowledge;
1028 if ((!client->vcm) || (!subsystem->updateEvent))
1031 UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
1032 if (!UpdateSubscriber)
1035 UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
1036 ClientEvent = peer->GetEventHandle(peer);
1037 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
1042 events[nCount++] = UpdateEvent;
1043 events[nCount++] = ClientEvent;
1044 events[nCount++] = ChannelEvent;
1045 events[nCount++] = MessageQueue_Event(MsgQueue);
1047 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1049 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
1051 if (client->activated)
1055 const RECTANGLE_16* rects;
1057 rects = region16_rects(&(subsystem->invalidRegion), &numRects);
1059 for (index = 0; index < numRects; index++)
1061 region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
1064 shadow_client_send_surface_update(client);
1068 * The return value of shadow_multiclient_consume is whether or not the subscriber really consumes the event.
1069 * It's not cared currently.
1071 (void)shadow_multiclient_consume(UpdateSubscriber);
1074 if (WaitForSingleObject(ClientEvent, 0) == WAIT_OBJECT_0)
1076 if (!peer->CheckFileDescriptor(peer))
1078 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
1083 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
1085 if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
1087 WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
1092 if (WaitForSingleObject(MessageQueue_Event(MsgQueue), 0) == WAIT_OBJECT_0)
1094 /* Drain messages. Pointer update could be accumulated. */
1095 pointerPositionMsg.id = 0;
1096 pointerPositionMsg.Free= NULL;
1097 pointerAlphaMsg.id = 0;
1098 pointerAlphaMsg.Free = NULL;
1099 audioVolumeMsg.id = 0;
1100 audioVolumeMsg.Free = NULL;
1101 while (MessageQueue_Peek(MsgQueue, &message, TRUE))
1103 if (message.id == WMQ_QUIT)
1110 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
1111 /* Abandon previous message */
1112 shadow_client_free_queued_message(&pointerPositionMsg);
1113 CopyMemory(&pointerPositionMsg, &message, sizeof(wMessage));
1116 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
1117 /* Abandon previous message */
1118 shadow_client_free_queued_message(&pointerAlphaMsg);
1119 CopyMemory(&pointerAlphaMsg, &message, sizeof(wMessage));
1122 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
1123 /* Abandon previous message */
1124 shadow_client_free_queued_message(&audioVolumeMsg);
1125 CopyMemory(&audioVolumeMsg, &message, sizeof(wMessage));
1129 shadow_client_subsystem_process_message(client, &message);
1134 if (message.id == WMQ_QUIT)
1136 /* Release stored message */
1137 shadow_client_free_queued_message(&pointerPositionMsg);
1138 shadow_client_free_queued_message(&pointerAlphaMsg);
1139 shadow_client_free_queued_message(&audioVolumeMsg);
1144 /* Process accumulated messages if needed */
1145 if (pointerPositionMsg.id)
1147 shadow_client_subsystem_process_message(client, &pointerPositionMsg);
1149 if (pointerAlphaMsg.id)
1151 shadow_client_subsystem_process_message(client, &pointerAlphaMsg);
1153 if (audioVolumeMsg.id)
1155 shadow_client_subsystem_process_message(client, &audioVolumeMsg);
1161 /* Free channels early because we establish channels in post connect */
1162 shadow_client_channels_free(client);
1164 if (UpdateSubscriber)
1166 shadow_multiclient_release_subscriber(UpdateSubscriber);
1167 UpdateSubscriber = NULL;
1171 peer->Disconnect(peer);
1173 freerdp_peer_context_free(peer);
1174 freerdp_peer_free(peer);
1179 BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
1181 rdpShadowClient* client;
1182 rdpShadowServer* server;
1184 server = (rdpShadowServer*) listener->info;
1186 peer->ContextExtra = (void*) server;
1187 peer->ContextSize = sizeof(rdpShadowClient);
1188 peer->ContextNew = (psPeerContextNew) shadow_client_context_new;
1189 peer->ContextFree = (psPeerContextFree) shadow_client_context_free;
1191 if (!freerdp_peer_context_new(peer))
1194 client = (rdpShadowClient*) peer->context;
1196 if (!(client->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)
1197 shadow_client_thread, client, 0, NULL)))
1199 freerdp_peer_context_free(peer);
1206 static void shadow_msg_out_addref(wMessage* message)
1208 SHADOW_MSG_OUT* msg = (SHADOW_MSG_OUT *)message->wParam;
1209 InterlockedIncrement(&(msg->refCount));
1212 static void shadow_msg_out_release(wMessage* message)
1214 SHADOW_MSG_OUT* msg = (SHADOW_MSG_OUT *)message->wParam;
1215 if (InterlockedDecrement(&(msg->refCount)) <= 0)
1218 msg->Free(message->id, msg);
1222 static BOOL shadow_client_dispatch_msg(rdpShadowClient* client, wMessage* message)
1224 /* Add reference when it is posted */
1225 shadow_msg_out_addref(message);
1226 if (MessageQueue_Dispatch(client->MsgQueue, message))
1232 /* Release the reference since post failed */
1233 shadow_msg_out_release(message);
1238 BOOL shadow_client_post_msg(rdpShadowClient* client, void* context, UINT32 type, SHADOW_MSG_OUT* msg, void* lParam)
1240 wMessage message = {0};
1242 message.context = context;
1244 message.wParam = (void *)msg;
1245 message.lParam = lParam;
1246 message.Free = shadow_msg_out_release;
1248 return shadow_client_dispatch_msg(client, &message);
1251 int shadow_client_boardcast_msg(rdpShadowServer* server, void* context, UINT32 type, SHADOW_MSG_OUT* msg, void* lParam)
1253 wMessage message = {0};
1254 rdpShadowClient* client = NULL;
1258 message.context = context;
1260 message.wParam = (void *)msg;
1261 message.lParam = lParam;
1262 message.Free = shadow_msg_out_release;
1264 /* First add reference as we reference it in this function.
1265 * Therefore it would not be free'ed during post. */
1266 shadow_msg_out_addref(&message);
1268 ArrayList_Lock(server->clients);
1269 for (index = 0; index < ArrayList_Count(server->clients); index++)
1271 client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
1272 if (shadow_client_dispatch_msg(client, &message))
1277 ArrayList_Unlock(server->clients);
1279 /* Release the reference for this function */
1280 shadow_msg_out_release(&message);
1285 int shadow_client_boardcast_quit(rdpShadowServer* server, int nExitCode)
1287 wMessageQueue* queue = NULL;
1291 ArrayList_Lock(server->clients);
1292 for (index = 0; index < ArrayList_Count(server->clients); index++)
1294 queue = ((rdpShadowClient*)ArrayList_GetItem(server->clients, index))->MsgQueue;
1295 if (MessageQueue_PostQuit(queue, nExitCode))
1300 ArrayList_Unlock(server->clients);