21#include <freerdp/config.h>
24#include <winpr/assert.h>
25#include <winpr/cast.h>
26#include <winpr/file.h>
27#include <winpr/path.h>
28#include <winpr/synch.h>
29#include <winpr/thread.h>
30#include <winpr/sysinfo.h>
31#include <winpr/interlocked.h>
33#include <freerdp/log.h>
34#include <freerdp/utils/gfx.h>
35#include <freerdp/channels/drdynvc.h>
39#define TAG CLIENT_TAG("shadow")
44 BOOL gfxSurfaceCreated;
48static BOOL shadow_avc420_enabled(
const rdpShadowClient* client);
50static BOOL shadow_avc444_enabled(
const rdpShadowClient* client);
59#define BitmapUpdateProxy(client, bitmap) \
60 BitmapUpdateProxyEx((client), (bitmap), __FILE__, __LINE__, __func__)
62static BOOL BitmapUpdateProxyEx(rdpShadowClient* client,
const BITMAP_UPDATE* bitmap,
63 const char* file,
size_t line,
const char* fkt)
68 rdpShadowServer* server = client->server;
71 rdpContext* context = (rdpContext*)client;
73 rdpUpdate* update = context->update;
76 if (server->SupportMultiRectBitmapUpdates)
78 const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, bitmap);
81 const DWORD log_level = WLOG_ERROR;
82 wLog* log = WLog_Get(TAG);
83 if (WLog_IsLevelActive(log, log_level))
85 WLog_PrintTextMessage(log, log_level, line, file, fkt,
86 "BitmapUpdate[count %" PRIu32
"] failed", bitmap->number);
93 for (UINT32 x = 0; x < bitmap->number; x++)
99 cur.skipCompression = bitmap->skipCompression;
100 const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, &cur);
103 const DWORD log_level = WLOG_ERROR;
104 wLog* log = WLog_Get(TAG);
105 if (WLog_IsLevelActive(log, log_level))
107 WLog_PrintTextMessage(log, log_level, line, file, fkt,
108 "BitmapUpdate[count 1, at %" PRIu32
"] failed", x);
119static inline BOOL shadow_client_rdpgfx_new_surface(rdpShadowClient* client)
121 UINT error = CHANNEL_RC_OK;
124 RdpgfxServerContext* context =
nullptr;
125 rdpSettings* settings =
nullptr;
127 WINPR_ASSERT(client);
128 context = client->rdpgfx;
129 WINPR_ASSERT(context);
130 settings = ((rdpContext*)client)->settings;
131 WINPR_ASSERT(settings);
137 createSurface.pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
138 createSurface.surfaceId = client->surfaceId;
139 surfaceToOutput.outputOriginX = 0;
140 surfaceToOutput.outputOriginY = 0;
141 surfaceToOutput.surfaceId = client->surfaceId;
142 surfaceToOutput.reserved = 0;
143 IFCALLRET(context->CreateSurface, error, context, &createSurface);
147 WLog_ERR(TAG,
"CreateSurface failed with error %" PRIu32
"", error);
151 IFCALLRET(context->MapSurfaceToOutput, error, context, &surfaceToOutput);
155 WLog_ERR(TAG,
"MapSurfaceToOutput failed with error %" PRIu32
"", error);
163static inline BOOL shadow_client_rdpgfx_release_surface(rdpShadowClient* client)
165 UINT error = CHANNEL_RC_OK;
167 RdpgfxServerContext* context =
nullptr;
169 WINPR_ASSERT(client);
171 context = client->rdpgfx;
172 WINPR_ASSERT(context);
174 pdu.surfaceId = client->surfaceId++;
175 IFCALLRET(context->DeleteSurface, error, context, &pdu);
179 WLog_ERR(TAG,
"DeleteSurface failed with error %" PRIu32
"", error);
187static inline BOOL shadow_client_rdpgfx_reset_graphic(rdpShadowClient* client)
189 UINT error = CHANNEL_RC_OK;
191 RdpgfxServerContext* context =
nullptr;
192 rdpSettings* settings =
nullptr;
194 WINPR_ASSERT(client);
195 WINPR_ASSERT(client->rdpgfx);
197 context = client->rdpgfx;
198 WINPR_ASSERT(context);
200 settings = client->context.settings;
201 WINPR_ASSERT(settings);
205 pdu.monitorCount = client->subsystem->numMonitors;
206 pdu.monitorDefArray = client->subsystem->monitors;
207 IFCALLRET(context->ResetGraphics, error, context, &pdu);
211 WLog_ERR(TAG,
"ResetGraphics failed with error %" PRIu32
"", error);
215 client->first_frame = TRUE;
219static inline void shadow_client_free_queued_message(
void* obj)
221 wMessage* message = (wMessage*)obj;
223 WINPR_ASSERT(message);
226 message->Free(message);
227 message->Free =
nullptr;
231static void shadow_client_context_free(freerdp_peer* peer, rdpContext* context)
233 rdpShadowClient* client = (rdpShadowClient*)context;
234 rdpShadowServer* server =
nullptr;
240 server = client->server;
241 if (server && server->clients)
242 ArrayList_Remove(server->clients, (
void*)client);
244 shadow_encoder_free(client->encoder);
247 MessageQueue_Free(client->MsgQueue);
248 WTSCloseServer(client->vcm);
249 region16_uninit(&(client->invalidRegion));
250 DeleteCriticalSection(&(client->lock));
252 client->MsgQueue =
nullptr;
253 client->encoder =
nullptr;
254 client->vcm =
nullptr;
258static BOOL shadow_client_context_new(freerdp_peer* peer, rdpContext* context)
261 const char bind_address[] =
"bind-address,";
262 rdpShadowClient* client = (rdpShadowClient*)context;
263 rdpSettings* settings =
nullptr;
264 const rdpSettings* srvSettings =
nullptr;
265 rdpShadowServer* server =
nullptr;
266 const wObject cb = {
nullptr,
nullptr,
nullptr, shadow_client_free_queued_message,
nullptr };
268 WINPR_ASSERT(client);
270 WINPR_ASSERT(peer->context);
272 server = (rdpShadowServer*)peer->ContextExtra;
273 WINPR_ASSERT(server);
275 srvSettings = server->settings;
276 WINPR_ASSERT(srvSettings);
278 client->surfaceId = 1;
279 client->server = server;
280 client->subsystem = server->subsystem;
281 WINPR_ASSERT(client->subsystem);
283 settings = peer->context->settings;
284 WINPR_ASSERT(settings);
296 settings, FreeRDP_RemoteFxRlgrMode,
306 settings, FreeRDP_SupportGraphicsPipeline,
321 if (server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
322 strnlen(bind_address,
sizeof(bind_address))) != 0))
330 client->inLobby = TRUE;
331 client->mayView = server->mayView;
332 client->mayInteract = server->mayInteract;
334 if (!InitializeCriticalSectionAndSpinCount(&(client->lock), 4000))
337 region16_init(&(client->invalidRegion));
338 client->vcm = WTSOpenServerA((LPSTR)peer->context);
340 if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
343 if (!(client->MsgQueue = MessageQueue_New(&cb)))
346 if (!(client->encoder = shadow_encoder_new(client)))
349 if (!ArrayList_Append(server->clients, (
void*)client))
355 shadow_client_context_free(peer, context);
359static inline void shadow_client_mark_invalid(rdpShadowClient* client, UINT32 numRects,
362 WINPR_ASSERT(client);
363 WINPR_ASSERT(rects || (numRects == 0));
365 rdpSettings* settings = client->context.settings;
366 WINPR_ASSERT(settings);
368 EnterCriticalSection(&(client->lock));
373 for (UINT32 index = 0; index < numRects; index++)
375 if (!region16_union_rect(&(client->invalidRegion), &(client->invalidRegion),
387 if (!region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &screenRegion))
391 LeaveCriticalSection(&(client->lock));
401static inline BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client)
405 rdpShadowServer* server =
nullptr;
406 rdpSettings* settings =
nullptr;
409 WINPR_ASSERT(client);
410 server = client->server;
411 settings = client->context.settings;
413 WINPR_ASSERT(server);
414 WINPR_ASSERT(server->surface);
415 WINPR_ASSERT(settings);
417 WINPR_ASSERT(server->surface->width <= UINT16_MAX);
418 WINPR_ASSERT(server->surface->height <= UINT16_MAX);
419 viewport.right = (UINT16)server->surface->width;
420 viewport.bottom = (UINT16)server->surface->height;
422 if (server->shareSubRect)
424 if (!rectangles_intersection(&viewport, &(server->subRect), &viewport))
428 width = viewport.right - viewport.left;
429 height = viewport.bottom - viewport.top;
431 WINPR_ASSERT(width >= 0);
432 WINPR_ASSERT(width <= UINT16_MAX);
433 WINPR_ASSERT(height >= 0);
434 WINPR_ASSERT(height <= UINT16_MAX);
440static BOOL shadow_client_capabilities(freerdp_peer* peer)
442 rdpShadowSubsystem* subsystem =
nullptr;
443 rdpShadowClient* client =
nullptr;
448 client = (rdpShadowClient*)peer->context;
449 WINPR_ASSERT(client);
450 WINPR_ASSERT(client->server);
452 subsystem = client->server->subsystem;
453 WINPR_ASSERT(subsystem);
455 IFCALLRET(subsystem->ClientCapabilities, ret, subsystem, client);
458 WLog_WARN(TAG,
"subsystem->ClientCapabilities failed");
463static void shadow_reset_desktop_resize(rdpShadowClient* client)
465 WINPR_ASSERT(client);
466 client->resizeRequested = FALSE;
470static BOOL shadow_send_desktop_resize(rdpShadowClient* client)
473 rdpUpdate* update =
nullptr;
474 rdpSettings* settings =
nullptr;
475 const freerdp_peer* peer =
nullptr;
477 WINPR_ASSERT(client);
479 settings = client->context.settings;
480 peer = client->context.peer;
482 WINPR_ASSERT(client->server);
483 WINPR_ASSERT(client->server->surface);
485 const UINT32 resizeWidth = client->server->surface->width;
486 const UINT32 resizeHeight = client->server->surface->height;
488 if (client->resizeRequested)
490 if ((resizeWidth == client->resizeWidth) && (resizeHeight == client->resizeHeight))
495 "detected previous resize request for resolution %" PRIu32
"x%" PRIu32
496 ", still have %" PRIu32
"x%" PRIu32
", disconnecting peer",
497 resizeWidth, resizeHeight, w, h);
502 update = client->context.update;
503 WINPR_ASSERT(update);
504 WINPR_ASSERT(update->DesktopResize);
512 rc = update->DesktopResize(update->context);
513 WLog_INFO(TAG,
"Client %s resize requested (%" PRIu32
"x%" PRIu32
"@%" PRIu32
")",
514 peer->hostname, resizeWidth, resizeHeight,
516 client->resizeRequested = TRUE;
517 client->resizeWidth = resizeWidth;
518 client->resizeHeight = resizeHeight;
524static BOOL shadow_client_post_connect(freerdp_peer* peer)
527 rdpSettings* settings =
nullptr;
528 rdpShadowClient* client =
nullptr;
529 rdpShadowServer* server =
nullptr;
530 rdpShadowSubsystem* subsystem =
nullptr;
534 client = (rdpShadowClient*)peer->context;
535 WINPR_ASSERT(client);
537 settings = peer->context->settings;
538 WINPR_ASSERT(settings);
540 server = client->server;
541 WINPR_ASSERT(server);
543 subsystem = server->subsystem;
544 WINPR_ASSERT(subsystem);
552 const UINT32 MultifragMaxRequestSize =
554 if (MultifragMaxRequestSize < 0x3F0000)
557 settings, FreeRDP_NSCodec,
563 WLog_INFO(TAG,
"Client from %s is activated (%" PRIu32
"x%" PRIu32
"@%" PRIu32
")",
568 if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK)
571 shadow_client_mark_invalid(client, 0,
nullptr);
578 if (Username && Password)
586 if (subsystem->Authenticate)
588 authStatus = subsystem->Authenticate(subsystem, client, Username, Domain, Password);
593 WLog_ERR(TAG,
"client authentication failure: %d", authStatus);
598 if (subsystem->ClientConnect)
600 return subsystem->ClientConnect(subsystem, client);
607static inline void shadow_client_convert_rects(rdpShadowClient* client,
RECTANGLE_16* dst,
610 WINPR_ASSERT(client);
611 WINPR_ASSERT(client->server);
613 WINPR_ASSERT(src || (numRects == 0));
615 if (client->server->shareSubRect)
617 UINT16 offsetX = client->server->subRect.left;
618 UINT16 offsetY = client->server->subRect.top;
620 for (UINT32 i = 0; i < numRects; i++)
625 d->left = s->left + offsetX;
626 d->right = s->right + offsetX;
627 d->top = s->top + offsetY;
628 d->bottom = s->bottom + offsetY;
641static BOOL shadow_client_refresh_request(rdpShadowClient* client)
643 wMessage message = WINPR_C_ARRAY_INIT;
646 WINPR_ASSERT(client);
647 WINPR_ASSERT(client->subsystem);
649 MsgPipe = client->subsystem->MsgPipe;
650 WINPR_ASSERT(MsgPipe);
652 message.id = SHADOW_MSG_IN_REFRESH_REQUEST_ID;
653 message.wParam =
nullptr;
654 message.lParam =
nullptr;
655 message.context = (
void*)client;
656 message.Free =
nullptr;
657 return MessageQueue_Dispatch(MsgPipe->In, &message);
661static BOOL shadow_client_refresh_rect(rdpContext* context, BYTE count,
const RECTANGLE_16* areas)
663 rdpShadowClient* client = (rdpShadowClient*)context;
679 shadow_client_convert_rects(client, rects, areas, count);
680 shadow_client_mark_invalid(client, count, rects);
685 shadow_client_mark_invalid(client, 0,
nullptr);
688 return shadow_client_refresh_request(client);
692static BOOL shadow_client_suppress_output(rdpContext* context, BYTE allow,
const RECTANGLE_16* area)
694 rdpShadowClient* client = (rdpShadowClient*)context;
697 WINPR_ASSERT(client);
699 client->suppressOutput = !(allow);
705 shadow_client_convert_rects(client, ®ion, area, 1);
706 shadow_client_mark_invalid(client, 1, ®ion);
710 shadow_client_mark_invalid(client, 0,
nullptr);
714 return shadow_client_refresh_request(client);
718static BOOL shadow_client_activate(freerdp_peer* peer)
722 rdpShadowClient* client = (rdpShadowClient*)peer->context;
723 WINPR_ASSERT(client);
726 if (shadow_client_recalc_desktop_size(client))
727 return shadow_send_desktop_resize(client);
729 shadow_reset_desktop_resize(client);
730 client->activated = TRUE;
731 client->inLobby = !(client->mayView);
733 if (shadow_encoder_reset(client->encoder) < 0)
735 WLog_ERR(TAG,
"Failed to reset encoder");
740 return shadow_client_refresh_rect(&client->context, 0,
nullptr);
744static BOOL shadow_client_logon(freerdp_peer* peer,
const SEC_WINNT_AUTH_IDENTITY* identity,
748 char* user =
nullptr;
749 char* domain =
nullptr;
750 char* password =
nullptr;
751 rdpSettings* settings =
nullptr;
753 WINPR_UNUSED(automatic);
756 WINPR_ASSERT(identity);
758 WINPR_ASSERT(peer->context);
760 settings = peer->context->settings;
761 WINPR_ASSERT(settings);
763 if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
766 user = ConvertWCharNToUtf8Alloc(identity->User, identity->UserLength,
nullptr);
768 if (identity->Domain)
769 domain = ConvertWCharNToUtf8Alloc(identity->Domain, identity->DomainLength,
nullptr);
771 if (identity->Password)
773 ConvertWCharNToUtf8Alloc(identity->Password, identity->PasswordLength,
nullptr);
778 user = _strdup((
char*)identity->User);
780 if (identity->Domain)
781 domain = _strdup((
char*)identity->Domain);
783 if (identity->Password)
784 password = _strdup((
char*)identity->Password);
787 if ((identity->User && !user) || (identity->Domain && !domain) ||
788 (identity->Password && !password))
815static inline void shadow_client_common_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
825 WINPR_ASSERT(client);
826 WINPR_ASSERT(client->encoder);
827 client->encoder->lastAckframeId = frameId;
831static BOOL shadow_client_surface_frame_acknowledge(rdpContext* context, UINT32 frameId)
833 rdpShadowClient* client = (rdpShadowClient*)context;
834 shadow_client_common_frame_acknowledge(client, frameId);
838 WINPR_ASSERT(client);
839 WINPR_ASSERT(client->encoder);
840 client->encoder->queueDepth = QUEUE_DEPTH_UNAVAILABLE;
846shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
849 rdpShadowClient* client =
nullptr;
851 WINPR_ASSERT(context);
852 WINPR_ASSERT(frameAcknowledge);
854 client = (rdpShadowClient*)context->custom;
855 shadow_client_common_frame_acknowledge(client, frameAcknowledge->frameId);
857 WINPR_ASSERT(client);
858 WINPR_ASSERT(client->encoder);
859 client->encoder->queueDepth = frameAcknowledge->queueDepth;
860 return CHANNEL_RC_OK;
864static BOOL shadow_are_caps_filtered(
const rdpSettings* settings, UINT32 caps)
866 const UINT32 capList[] = {
867#if defined(WITH_GFX_AV1)
868 RDPGFX_CAPVERSION_FRDP_1,
870 RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10,
871 RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103,
872 RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106,
873 RDPGFX_CAPVERSION_106_ERR, RDPGFX_CAPVERSION_107
876 WINPR_ASSERT(settings);
879 for (UINT32 x = 0; x < ARRAYSIZE(capList); x++)
881 if (caps == capList[x])
882 return (filter & (1u << x)) != 0;
889static UINT shadow_client_send_caps_confirm(RdpgfxServerContext* context, rdpShadowClient* client,
892 WINPR_ASSERT(context);
893 WINPR_ASSERT(client);
896 WINPR_ASSERT(context->CapsConfirm);
897 UINT rc = context->CapsConfirm(context, pdu);
898 client->areGfxCapsReady = (rc == CHANNEL_RC_OK);
899 client->confirmedCaps = *pdu->capsSet;
901 rdpSettings* clientSettings = client->context.settings;
902 WINPR_ASSERT(clientSettings);
904#if defined(WITH_GFX_AV1)
905 if (pdu->capsSet->version == RDPGFX_CAPVERSION_FRDP_1)
907 UINT32 flags = FREERDP_CODEC_AV1_I420;
908 if ((pdu->capsSet->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) == 0)
909 flags = FREERDP_CODEC_AV1_I444;
911 if (shadow_encoder_prepare(client->encoder, flags) < 0)
912 return ERROR_INVALID_PARAMETER;
916 if (shadow_avc444_enabled(client) || shadow_avc420_enabled(client))
919 const BOOL h264 = (shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 |
920 FREERDP_CODEC_AVC444) >= 0);
924 clientSettings, FreeRDP_GfxH264,
925 (pdu->capsSet->flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED) != 0))
947static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, rdpShadowClient* client,
949 UINT32 capsSetCount, UINT32 capsVersion, UINT* rc)
951 WINPR_ASSERT(context);
952 WINPR_ASSERT(client);
953 WINPR_ASSERT(capsSets || (capsSetCount == 0));
956 WINPR_ASSERT(context->rdpcontext);
957 const rdpSettings* srvSettings = context->rdpcontext->settings;
958 WINPR_ASSERT(srvSettings);
960 rdpSettings* clientSettings = client->context.settings;
961 WINPR_ASSERT(clientSettings);
963 if (shadow_are_caps_filtered(srvSettings, capsVersion))
966 for (UINT32 index = 0; index < capsSetCount; index++)
970 WLog_INFO(TAG,
"testing %s vs %s[0x%08" PRIx32
"]",
971 rdpgfx_caps_version_str(currentCaps->version),
972 rdpgfx_caps_version_str(capsVersion), capsVersion);
973 if (currentCaps->version == capsVersion)
979 const UINT32 flags = pdu.capsSet->flags;
982 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
986 BOOL avc444 = !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED);
987 BOOL avc444v2 = avc444;
1004 const BOOL progressivev2 =
1016#if defined(WITH_GFX_AV1)
1020 const UINT32 av1Profile =
1027 if (!h264 || (!avc444v2 && !avc444 && !avc420))
1028 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
1030#if defined(WITH_GFX_AV1)
1031 if (currentCaps->version == RDPGFX_CAPVERSION_FRDP_1)
1036 pdu.capsSet->flags &=
1037 ~(RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED | RDPGFX_CAPS_FLAG_AV1_I444_DISABLED);
1039 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) != 0)
1041 if (av1Profile == 0)
1045 if ((av1Profile == 0) ||
1046 ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) == 0))
1047 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1048 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1049 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1052 *rc = shadow_client_send_caps_confirm(context, client, &pdu);
1066static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context,
1069 UINT rc = ERROR_INTERNAL_ERROR;
1073 WINPR_ASSERT(context);
1074 WINPR_ASSERT(capsAdvertise);
1076 rdpShadowClient* client = (rdpShadowClient*)context->custom;
1077 WINPR_ASSERT(client);
1078 WINPR_ASSERT(context->rdpcontext);
1080 const rdpSettings* srvSettings = context->rdpcontext->settings;
1081 WINPR_ASSERT(srvSettings);
1083 rdpSettings* clientSettings = client->context.settings;
1084 WINPR_ASSERT(clientSettings);
1087 if (!shadow_client_refresh_rect(&client->context, 0,
nullptr))
1090 const UINT32 capsVersions[] = {
1091#if defined(WITH_GFX_AV1)
1092 RDPGFX_CAPVERSION_FRDP_1,
1094 RDPGFX_CAPVERSION_107, RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
1095 RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_103,
1096 RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_10,
1100 shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444) >= 0;
1102#if defined(WITH_GFX_AV1)
1106 const UINT32 profile =
1111 codec = FREERDP_CODEC_AV1_I420;
1114 codec = FREERDP_CODEC_AV1_I444;
1117 return ERROR_BAD_PROFILE;
1119 const BOOL av1 = shadow_encoder_prepare(client->encoder, codec) >= 0;
1123 return ERROR_INTERNAL_ERROR;
1128 for (
size_t x = 0; x < ARRAYSIZE(capsVersions); x++)
1130 const UINT32 cur = capsVersions[x];
1131 if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1132 capsAdvertise->capsSetCount, cur, &rc))
1136 if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_81))
1138 for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1140 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1142 if (currentCaps->version == RDPGFX_CAPVERSION_81)
1146 pdu.capsSet = ∩︀
1148 flags = pdu.capsSet->flags;
1156 (flags & RDPGFX_CAPS_FLAG_THINCLIENT) != 0))
1159 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1162#ifndef WITH_GFX_H264
1166 pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
1171 return shadow_client_send_caps_confirm(context, client, &pdu);
1176 if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_8))
1178 for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1180 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1182 if (currentCaps->version == RDPGFX_CAPVERSION_8)
1186 pdu.capsSet = ∩︀
1187 flags = pdu.capsSet->flags;
1197 (flags & RDPGFX_CAPS_FLAG_THINCLIENT) != 0))
1200 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1203 return shadow_client_send_caps_confirm(context, client, &pdu);
1208 return CHANNEL_RC_UNSUPPORTED_VERSION;
1215 WINPR_ASSERT(havc420);
1216 return sizeof(UINT32)
1218 * havc420->meta.numRegionRects +
1222#if defined(WITH_GFX_AV1)
1224static BOOL shadow_client_send_av1(rdpShadowClient* client,
const BYTE* pSrcData, UINT32 nSrcStep,
1225 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1230 WINPR_ASSERT(client);
1232 rdpShadowEncoder* encoder = client->encoder;
1233 WINPR_ASSERT(encoder);
1235 UINT error = CHANNEL_RC_OK;
1240 UINT32 flags = FREERDP_CODEC_AV1_I444;
1241 if ((client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1242 flags = FREERDP_CODEC_AV1_I420;
1244 if (shadow_encoder_prepare(encoder, flags) < 0)
1246 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_AV1");
1250 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1251 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1252 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1253 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1254 regionRect.left = (UINT16)cmd->left;
1255 regionRect.top = (UINT16)cmd->top;
1256 regionRect.right = (UINT16)cmd->right;
1257 regionRect.bottom = (UINT16)cmd->bottom;
1258 rc = freerdp_av1_compress(encoder->av1, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight,
1259 ®ionRect, &avc420.data, &avc420.length, &avc420.meta);
1262 WLog_ERR(TAG,
"freerdp_av1_compress failed");
1269 cmd->codecId = RDPGFX_CODECID_AV1;
1270 cmd->extra = (
void*)&avc420;
1272 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1274 cmd->extra =
nullptr;
1276 free_h264_metablock(&avc420.meta);
1280 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1288static BOOL shadow_client_send_avc444(rdpShadowClient* client,
const BYTE* pSrcData,
1289 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1294 WINPR_ASSERT(client);
1296 rdpShadowEncoder* encoder = client->encoder;
1297 WINPR_ASSERT(encoder);
1299 UINT error = CHANNEL_RC_OK;
1303 const BOOL GfxAVC444v2 = (cmd->codecId == RDPGFX_CODECID_AVC444v2);
1304 BYTE version = GfxAVC444v2 ? 2 : 1;
1306 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC444) < 0)
1308 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_AVC444");
1312 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1313 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1314 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1315 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1316 regionRect.left = (UINT16)cmd->left;
1317 regionRect.top = (UINT16)cmd->top;
1318 regionRect.right = (UINT16)cmd->right;
1319 regionRect.bottom = (UINT16)cmd->bottom;
1320 rc = avc444_compress(encoder->h264, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, version,
1321 ®ionRect, &avc444.LC, &avc444.bitstream[0].data,
1322 &avc444.bitstream[0].length, &avc444.bitstream[1].data,
1323 &avc444.bitstream[1].length, &avc444.bitstream[0].meta,
1324 &avc444.bitstream[1].meta);
1327 WLog_ERR(TAG,
"avc420_compress failed for avc444");
1334 avc444.cbAvc420EncodedBitstream1 = rdpgfx_estimate_h264_avc420(&avc444.bitstream[0]);
1335 cmd->extra = (
void*)&avc444;
1336 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1338 cmd->extra =
nullptr;
1341 free_h264_metablock(&avc444.bitstream[0].meta);
1342 free_h264_metablock(&avc444.bitstream[1].meta);
1345 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1352static BOOL shadow_client_send_avc420(rdpShadowClient* client,
const BYTE* pSrcData,
1353 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1358 WINPR_ASSERT(client);
1360 rdpShadowEncoder* encoder = client->encoder;
1361 WINPR_ASSERT(encoder);
1363 UINT error = CHANNEL_RC_OK;
1368 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420) < 0)
1370 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_AVC420");
1374 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1375 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1376 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1377 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1378 regionRect.left = (UINT16)cmd->left;
1379 regionRect.top = (UINT16)cmd->top;
1380 regionRect.right = (UINT16)cmd->right;
1381 regionRect.bottom = (UINT16)cmd->bottom;
1382 rc = avc420_compress(encoder->h264, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, ®ionRect,
1383 &avc420.data, &avc420.length, &avc420.meta);
1386 WLog_ERR(TAG,
"avc420_compress failed");
1393 cmd->codecId = RDPGFX_CODECID_AVC420;
1394 cmd->extra = (
void*)&avc420;
1395 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1397 cmd->extra =
nullptr;
1399 free_h264_metablock(&avc420.meta);
1403 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1410static BOOL shadow_client_send_rfx(rdpShadowClient* client,
const BYTE* pSrcData, UINT32 nSrcStep,
1411 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1416 WINPR_ASSERT(client);
1418 rdpShadowEncoder* encoder = client->encoder;
1419 WINPR_ASSERT(encoder);
1421 UINT error = CHANNEL_RC_OK;
1425 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
1427 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
1431 const UINT32 rfxFormat = rfx_context_get_pixel_format(encoder->rfx);
1432 if (rfxFormat != SrcFormat)
1434 WLog_ERR(TAG,
"RFX context pixel format mismatch %s, expected %s",
1435 FreeRDPGetColorFormatName(rfxFormat), FreeRDPGetColorFormatName(SrcFormat));
1439 wStream* s = Stream_New(
nullptr, 1024);
1442 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1443 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1444 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1445 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1446 rect.x = (UINT16)cmd->left;
1447 rect.y = (UINT16)cmd->top;
1448 rect.width = WINPR_ASSERTING_INT_CAST(UINT16, cmd->right - cmd->left);
1449 rect.height = WINPR_ASSERTING_INT_CAST(UINT16, cmd->bottom - cmd->top);
1451 rc = rfx_compose_message(encoder->rfx, s, &rect, 1, pSrcData, nWidth, nHeight, nSrcStep);
1455 WLog_ERR(TAG,
"rfx_compose_message failed");
1456 Stream_Free(s, TRUE);
1463 const size_t pos = Stream_GetPosition(s);
1464 WINPR_ASSERT(pos <= UINT32_MAX);
1466 cmd->codecId = RDPGFX_CODECID_CAVIDEO;
1467 cmd->data = Stream_Buffer(s);
1468 cmd->length = (UINT32)pos;
1470 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1472 cmd->data =
nullptr;
1475 Stream_Free(s, TRUE);
1478 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1485static BOOL shadow_client_send_progressive(rdpShadowClient* client,
const BYTE* pSrcData,
1486 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1491 WINPR_ASSERT(client);
1493 rdpShadowEncoder* encoder = client->encoder;
1494 WINPR_ASSERT(encoder);
1496 UINT error = CHANNEL_RC_OK;
1501 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PROGRESSIVE) < 0)
1503 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_PROGRESSIVE");
1507 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1508 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1509 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1510 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1511 regionRect.left = (UINT16)cmd->left;
1512 regionRect.top = (UINT16)cmd->top;
1513 regionRect.right = (UINT16)cmd->right;
1514 regionRect.bottom = (UINT16)cmd->bottom;
1515 region16_init(®ion);
1516 if (!region16_union_rect(®ion, ®ion, ®ionRect))
1518 region16_uninit(®ion);
1521 rc = progressive_compress(encoder->progressive, pSrcData, nSrcStep * nHeight, SrcFormat, nWidth,
1522 nHeight, nSrcStep, ®ion, &cmd->data, &cmd->length);
1523 region16_uninit(®ion);
1526 WLog_ERR(TAG,
"progressive_compress failed");
1533 cmd->codecId = RDPGFX_CODECID_CAPROGRESSIVE;
1535 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1538 cmd->data =
nullptr;
1542 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1549static BOOL shadow_client_send_planar(rdpShadowClient* client,
const BYTE* pSrcData,
1550 UINT32 nSrcStep, UINT32 SrcFormat,
1555 WINPR_ASSERT(client);
1557 rdpShadowEncoder* encoder = client->encoder;
1558 WINPR_ASSERT(encoder);
1560 UINT error = CHANNEL_RC_OK;
1561 const UINT32 w = cmd->right - cmd->left;
1562 const UINT32 h = cmd->bottom - cmd->top;
1564 &pSrcData[cmd->top * nSrcStep + cmd->left * FreeRDPGetBytesPerPixel(SrcFormat)];
1565 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
1567 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_PLANAR");
1571 const BOOL rc = freerdp_bitmap_planar_context_reset(encoder->planar, w, h);
1575 freerdp_planar_topdown_image(encoder->planar, TRUE);
1577 cmd->data = freerdp_bitmap_compress_planar(encoder->planar, src, SrcFormat, w, h, nSrcStep,
1578 nullptr, &cmd->length);
1579 WINPR_ASSERT(cmd->data || (cmd->length == 0));
1581 cmd->codecId = RDPGFX_CODECID_PLANAR;
1583 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart, cmdend);
1585 cmd->data =
nullptr;
1589 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1596static BOOL shadow_client_send_uncompressed(rdpShadowClient* client,
const BYTE* pSrcData,
1597 UINT32 nSrcStep, UINT32 SrcFormat,
1602 WINPR_ASSERT(client);
1604 UINT error = CHANNEL_RC_OK;
1605 const UINT32 w = cmd->right - cmd->left;
1606 const UINT32 h = cmd->bottom - cmd->top;
1607 const UINT32 length = w * 4 * h;
1609 BYTE* data = malloc(length);
1613 BOOL rc = freerdp_image_copy_no_overlap(data, cmd->format, 0, 0, 0, w, h, pSrcData, SrcFormat,
1614 nSrcStep, cmd->left, cmd->top,
nullptr, 0);
1622 cmd->length = length;
1623 cmd->codecId = RDPGFX_CODECID_UNCOMPRESSED;
1625 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart, cmdend);
1627 cmd->data =
nullptr;
1630 WLog_ERR(TAG,
"SurfaceFrameCommand failed with error %" PRIu32
"", error);
1637static BOOL shadow_avc444_enabled(
const rdpShadowClient* client)
1639 WINPR_ASSERT(client);
1640 switch (client->confirmedCaps.version)
1642 case RDPGFX_CAPVERSION_10:
1643 case RDPGFX_CAPVERSION_101:
1644 case RDPGFX_CAPVERSION_102:
1645 case RDPGFX_CAPVERSION_103:
1646 case RDPGFX_CAPVERSION_104:
1647 case RDPGFX_CAPVERSION_105:
1648 case RDPGFX_CAPVERSION_106:
1649 case RDPGFX_CAPVERSION_107:
1650 return (client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0;
1658static BOOL shadow_avc420_enabled(
const rdpShadowClient* client)
1660 if (shadow_avc444_enabled(client))
1662 if (client->confirmedCaps.version != RDPGFX_CAPVERSION_81)
1664 return (client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED) != 0;
1673static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client,
const BYTE* pSrcData,
1674 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nXSrc,
1675 UINT16 nYSrc, UINT16 nWidth, UINT16 nHeight)
1677 const rdpContext* context = (
const rdpContext*)client;
1683 if (!context || !pSrcData)
1686 const rdpSettings* settings = context->settings;
1687 rdpShadowEncoder* encoder = client->encoder;
1689 if (!settings || !encoder)
1692 if (client->first_frame)
1696 if (!rfx_context_reset(encoder->rfx, nWidth, nHeight))
1699 client->first_frame = FALSE;
1702 cmdstart.frameId = shadow_encoder_create_frame_id(encoder);
1703 GetSystemTime(&sTime);
1704 cmdstart.timestamp = (UINT32)(sTime.wHour << 22U | sTime.wMinute << 16U | sTime.wSecond << 10U |
1705 sTime.wMilliseconds);
1706 cmdend.frameId = cmdstart.frameId;
1707 cmd.surfaceId = client->surfaceId;
1708 cmd.format = PIXEL_FORMAT_BGRX32;
1711 cmd.right = cmd.left + nWidth;
1712 cmd.bottom = cmd.top + nHeight;
1714 cmd.height = nHeight;
1716#if defined(WITH_GFX_AV1)
1719 if (client->confirmedCaps.version == RDPGFX_CAPVERSION_FRDP_1)
1721 return shadow_client_send_av1(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
1722 &cmd, &cmdstart, &cmdend);
1732 if (GfxAVC444 || GfxAVC444v2)
1734 if (shadow_avc444_enabled(client))
1736 cmd.codecId = GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444;
1737 return shadow_client_send_avc444(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
1738 &cmd, &cmdstart, &cmdend);
1742 if (GfxH264 && shadow_avc420_enabled(client))
1744 return shadow_client_send_avc420(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
1745 &cmd, &cmdstart, &cmdend);
1751 return shadow_client_send_rfx(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight, &cmd,
1752 &cmdstart, &cmdend);
1757 return shadow_client_send_progressive(client, pSrcData, nSrcStep, SrcFormat, nWidth,
1758 nHeight, &cmd, &cmdstart, &cmdend);
1763 return shadow_client_send_planar(client, pSrcData, nSrcStep, SrcFormat, &cmd, &cmdstart,
1767 return shadow_client_send_uncompressed(client, pSrcData, nSrcStep, SrcFormat, &cmd, &cmdstart,
1772static BOOL stream_surface_bits_supported(
const rdpSettings* settings)
1774 const UINT32 supported =
1776 return ((supported & SURFCMDS_STREAM_SURFACE_BITS) != 0);
1780static BOOL set_surface_bits_supported(
const rdpSettings* settings)
1782 const UINT32 supported =
1784 return ((supported & SURFCMDS_SET_SURFACE_BITS) != 0);
1788static BOOL is_surface_command_supported(
const rdpSettings* settings)
1790 if (stream_surface_bits_supported(settings))
1794 if (supported && (rfxID != 0))
1797 if (set_surface_bits_supported(settings))
1801 if (supported && (nsID != 0))
1813static BOOL shadow_client_send_surface_bits(rdpShadowClient* client, BYTE* pSrcData,
1814 UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
1815 UINT16 nWidth, UINT16 nHeight)
1821 size_t numMessages = 0;
1823 rdpUpdate* update =
nullptr;
1824 rdpContext* context = (rdpContext*)client;
1825 rdpSettings* settings =
nullptr;
1826 rdpShadowEncoder* encoder =
nullptr;
1829 if (!context || !pSrcData)
1832 update = context->update;
1833 settings = context->settings;
1834 encoder = client->encoder;
1836 if (!update || !settings || !encoder)
1839 if (encoder->frameAck)
1840 frameId = shadow_encoder_create_frame_id(encoder);
1845 if (stream_surface_bits_supported(settings) &&
1848 RFX_RECT rect = WINPR_C_ARRAY_INIT;
1850 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
1852 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
1859 rect.width = nWidth;
1860 rect.height = nHeight;
1862 const UINT32 MultifragMaxRequestSize =
1864 RFX_MESSAGE_LIST* messages =
1865 rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
1868 nSrcStep, &numMessages, MultifragMaxRequestSize);
1871 WLog_ERR(TAG,
"rfx_encode_messages failed");
1875 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
1876 WINPR_ASSERT(rfxID <= UINT16_MAX);
1877 cmd.bmp.codecID = (UINT16)rfxID;
1888 cmd.skipCompression = TRUE;
1890 for (
size_t i = 0; i < numMessages; i++)
1892 Stream_ResetPosition(s);
1894 const RFX_MESSAGE* msg = rfx_message_list_get(messages, i);
1895 if (!rfx_write_message(encoder->rfx, s, msg))
1897 WLog_ERR(TAG,
"rfx_write_message failed");
1902 cmd.bmp.bitmapDataLength = WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetPosition(s));
1903 cmd.bmp.bitmapData = Stream_Buffer(s);
1905 last = ((i + 1) == numMessages);
1907 if (!encoder->frameAck)
1908 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
1910 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last,
1915 WLog_ERR(TAG,
"Send surface bits(RemoteFxCodec) failed");
1920 rfx_message_list_free(messages);
1922 else if (set_surface_bits_supported(settings) &&
1925 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC) < 0)
1927 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_NSCODEC");
1932 Stream_ResetPosition(s);
1933 pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
1934 if (!nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep))
1937 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
1939 WINPR_ASSERT(nsID <= UINT16_MAX);
1940 cmd.bmp.codecID = (UINT16)nsID;
1941 cmd.destLeft = nXSrc;
1942 cmd.destTop = nYSrc;
1943 cmd.destRight = cmd.destLeft + nWidth;
1944 cmd.destBottom = cmd.destTop + nHeight;
1945 cmd.bmp.width = nWidth;
1946 cmd.bmp.height = nHeight;
1948 cmd.bmp.bitmapDataLength = WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetPosition(s));
1949 cmd.bmp.bitmapData = Stream_Buffer(s);
1953 if (!encoder->frameAck)
1954 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
1956 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last, frameId);
1960 WLog_ERR(TAG,
"Send surface bits(NSCodec) failed");
1973static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrcData,
1974 UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
1975 UINT16 nWidth, UINT16 nHeight)
1978 BYTE* data =
nullptr;
1979 BYTE* buffer =
nullptr;
1986 UINT32 SrcFormat = 0;
1988 rdpContext* context = (rdpContext*)client;
1989 UINT32 totalBitmapSize = 0;
1990 UINT32 updateSizeEstimate = 0;
1994 if (!context || !pSrcData)
1997 rdpUpdate* update = context->update;
1998 rdpSettings* settings = context->settings;
1999 rdpShadowEncoder* encoder = client->encoder;
2001 if (!update || !settings || !encoder)
2004 const UINT32 maxUpdateSize =
2008 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED) < 0)
2010 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_INTERLEAVED");
2016 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
2018 WLog_ERR(TAG,
"Failed to prepare encoder FREERDP_CODEC_PLANAR");
2023 SrcFormat = PIXEL_FORMAT_BGRX32;
2025 if ((nXSrc % 4) != 0)
2027 nWidth += (nXSrc % 4);
2028 nXSrc -= (nXSrc % 4);
2031 if ((nYSrc % 4) != 0)
2033 nHeight += (nYSrc % 4);
2034 nYSrc -= (nYSrc % 4);
2037 rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
2038 cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
2040 totalBitmapSize = 0;
2041 bitmapUpdate.number = rows * cols;
2046 bitmapUpdate.rectangles = bitmapData;
2048 if ((nWidth % 4) != 0)
2050 nWidth += (4 - (nWidth % 4));
2053 if ((nHeight % 4) != 0)
2055 nHeight += (4 - (nHeight % 4));
2058 for (yIdx = 0; yIdx < rows; yIdx++)
2060 for (xIdx = 0; xIdx < cols; xIdx++)
2062 bitmap = &bitmapData[k];
2064 bitmap->height = 64;
2065 bitmap->destLeft = nXSrc + (xIdx * 64);
2066 bitmap->destTop = nYSrc + (yIdx * 64);
2068 if (((INT64)bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
2069 bitmap->width = (UINT32)(nXSrc + nWidth) - bitmap->destLeft;
2071 if (((INT64)bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
2072 bitmap->height = (UINT32)(nYSrc + nHeight) - bitmap->destTop;
2074 bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
2075 bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
2076 bitmap->compressed = TRUE;
2078 if ((bitmap->width < 4) || (bitmap->height < 4))
2084 UINT32 bytesPerPixel = (bitsPerPixel + 7) / 8;
2085 DstSize = 64 * 64 * 4;
2086 buffer = encoder->grid[k];
2088 ret = interleaved_compress(
2089 encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height, pSrcData,
2090 SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop,
nullptr, bitsPerPixel);
2093 bitmap->bitmapDataStream = buffer;
2094 bitmap->bitmapLength = DstSize;
2095 bitmap->bitsPerPixel = bitsPerPixel;
2096 bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
2097 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
2102 buffer = encoder->grid[k];
2103 data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
2106 freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, bitmap->width,
2107 bitmap->height, nSrcStep, buffer, &dstSize);
2108 bitmap->bitmapDataStream = buffer;
2109 bitmap->bitmapLength = dstSize;
2110 bitmap->bitsPerPixel = 32;
2111 bitmap->cbScanWidth = bitmap->width * 4;
2112 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
2115 bitmap->cbCompFirstRowSize = 0;
2116 bitmap->cbCompMainBodySize = bitmap->bitmapLength;
2117 totalBitmapSize += bitmap->bitmapLength;
2122 bitmapUpdate.number = k;
2123 updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.number) + 16;
2125 if (updateSizeEstimate > maxUpdateSize)
2129 UINT32 updateSize = 0;
2130 UINT32 newUpdateSize = 0;
2136 if (!fragBitmapData)
2138 WLog_ERR(TAG,
"Failed to allocate memory for fragBitmapData");
2143 bitmapUpdate.rectangles = fragBitmapData;
2149 newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
2151 if (newUpdateSize < maxUpdateSize)
2153 CopyMemory(&fragBitmapData[j++], &bitmapData[i++],
sizeof(
BITMAP_DATA));
2154 updateSize = newUpdateSize;
2157 if ((newUpdateSize >= maxUpdateSize) || (i + 1) >= k)
2159 bitmapUpdate.number = j;
2160 ret = BitmapUpdateProxy(client, &bitmapUpdate);
2170 free(fragBitmapData);
2174 ret = BitmapUpdateProxy(client, &bitmapUpdate);
2188static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2195 rdpContext* context = (rdpContext*)client;
2196 rdpSettings* settings =
nullptr;
2197 rdpShadowServer* server =
nullptr;
2198 rdpShadowSurface* surface =
nullptr;
2202 BYTE* pSrcData =
nullptr;
2203 UINT32 nSrcStep = 0;
2204 UINT32 SrcFormat = 0;
2205 UINT32 numRects = 0;
2208 if (!context || !pStatus)
2211 settings = context->settings;
2212 server = client->server;
2214 if (!settings || !server)
2217 surface = client->inLobby ? server->lobby : server->surface;
2223 EnterCriticalSection(&(client->lock));
2224 region16_init(&invalidRegion);
2226 const BOOL res = region16_copy(&invalidRegion, &(client->invalidRegion));
2227 region16_clear(&(client->invalidRegion));
2228 LeaveCriticalSection(&(client->lock));
2233 EnterCriticalSection(&surface->lock);
2234 rects = region16_rects(&(surface->invalidRegion), &numRects);
2236 for (UINT32 index = 0; index < numRects; index++)
2238 if (!region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]))
2242 surfaceRect.left = 0;
2243 surfaceRect.top = 0;
2244 WINPR_ASSERT(surface->width <= UINT16_MAX);
2245 WINPR_ASSERT(surface->height <= UINT16_MAX);
2246 surfaceRect.right = (UINT16)surface->width;
2247 surfaceRect.bottom = (UINT16)surface->height;
2248 if (!region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect))
2251 if (server->shareSubRect)
2253 if (!region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect)))
2257 if (region16_is_empty(&invalidRegion))
2263 extents = region16_extents(&invalidRegion);
2264 nXSrc = extents->left;
2265 nYSrc = extents->top;
2266 nWidth = extents->right - extents->left;
2267 nHeight = extents->bottom - extents->top;
2268 pSrcData = surface->data;
2269 nSrcStep = surface->scanline;
2270 SrcFormat = surface->format;
2273 if (server->shareSubRect)
2277 subX = server->subRect.left;
2278 subY = server->subRect.top;
2281 WINPR_ASSERT(nXSrc >= 0);
2282 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2283 WINPR_ASSERT(nYSrc >= 0);
2284 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2285 pSrcData = &pSrcData[((UINT16)subY * nSrcStep) + ((UINT16)subX * 4U)];
2294 if (pStatus->gfxOpened && client->areGfxCapsReady)
2301 if (!pStatus->gfxSurfaceCreated)
2304 if (!(ret = shadow_client_rdpgfx_reset_graphic(client)))
2307 if (!(ret = shadow_client_rdpgfx_new_surface(client)))
2310 pStatus->gfxSurfaceCreated = TRUE;
2313 WINPR_ASSERT(nWidth >= 0);
2314 WINPR_ASSERT(nWidth <= UINT16_MAX);
2315 WINPR_ASSERT(nHeight >= 0);
2316 WINPR_ASSERT(nHeight <= UINT16_MAX);
2317 ret = shadow_client_send_surface_gfx(client, pSrcData, nSrcStep, SrcFormat, 0, 0,
2318 (UINT16)nWidth, (UINT16)nHeight);
2325 else if (is_surface_command_supported(settings))
2327 WINPR_ASSERT(nXSrc >= 0);
2328 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2329 WINPR_ASSERT(nYSrc >= 0);
2330 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2331 WINPR_ASSERT(nWidth >= 0);
2332 WINPR_ASSERT(nWidth <= UINT16_MAX);
2333 WINPR_ASSERT(nHeight >= 0);
2334 WINPR_ASSERT(nHeight <= UINT16_MAX);
2335 ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, (UINT16)nXSrc,
2336 (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
2340 WINPR_ASSERT(nXSrc >= 0);
2341 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2342 WINPR_ASSERT(nYSrc >= 0);
2343 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2344 WINPR_ASSERT(nWidth >= 0);
2345 WINPR_ASSERT(nWidth <= UINT16_MAX);
2346 WINPR_ASSERT(nHeight >= 0);
2347 WINPR_ASSERT(nHeight <= UINT16_MAX);
2348 ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, (UINT16)nXSrc,
2349 (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
2353 LeaveCriticalSection(&surface->lock);
2354 region16_uninit(&invalidRegion);
2366static BOOL shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2368 rdpContext* context = (rdpContext*)client;
2369 rdpSettings* settings =
nullptr;
2370 freerdp_peer* peer =
nullptr;
2372 if (!context || !pStatus)
2375 peer = context->peer;
2376 settings = context->settings;
2378 if (!peer || !settings)
2386 client->activated = FALSE;
2389 if (pStatus->gfxSurfaceCreated)
2391 if (!shadow_client_rdpgfx_release_surface(client))
2394 pStatus->gfxSurfaceCreated = FALSE;
2398 if (!shadow_send_desktop_resize(client))
2400 shadow_reset_desktop_resize(client);
2403 EnterCriticalSection(&(client->lock));
2404 region16_clear(&(client->invalidRegion));
2405 LeaveCriticalSection(&(client->lock));
2416static BOOL shadow_client_surface_update(rdpShadowClient* client,
REGION16* region)
2418 UINT32 numRects = 0;
2420 rects = region16_rects(region, &numRects);
2421 shadow_client_mark_invalid(client, numRects, rects);
2432static inline BOOL shadow_client_no_surface_update(rdpShadowClient* client,
2433 SHADOW_GFX_STATUS* pStatus)
2435 rdpShadowServer* server =
nullptr;
2436 rdpShadowSurface* surface =
nullptr;
2437 WINPR_UNUSED(pStatus);
2438 WINPR_ASSERT(client);
2439 server = client->server;
2440 WINPR_ASSERT(server);
2441 surface = client->inLobby ? server->lobby : server->surface;
2442 EnterCriticalSection(&surface->lock);
2443 const BOOL rc = shadow_client_surface_update(client, &(surface->invalidRegion));
2444 LeaveCriticalSection(&surface->lock);
2449static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
2451 rdpContext* context = (rdpContext*)client;
2453 WINPR_ASSERT(message);
2454 WINPR_ASSERT(context);
2456 rdpUpdate* update = context->update;
2457 WINPR_ASSERT(update);
2461 switch (message->id)
2463 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
2468 pointerPosition.xPos = msg->xPos;
2469 pointerPosition.yPos = msg->yPos;
2471 WINPR_ASSERT(client->server);
2472 if (client->server->shareSubRect)
2474 pointerPosition.xPos -= client->server->subRect.left;
2475 pointerPosition.yPos -= client->server->subRect.top;
2478 if (client->activated)
2480 if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
2482 WINPR_ASSERT(update->pointer);
2483 if (!IFCALLRESULT(TRUE, update->pointer->PointerPosition, context,
2486 client->pointerX = msg->xPos;
2487 client->pointerY = msg->yPos;
2494 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
2503 pointerNew.xorBpp = 24;
2504 pointerColor = &(pointerNew.colorPtrAttr);
2505 pointerColor->cacheIndex = 0;
2506 pointerColor->hotSpotX = WINPR_ASSERTING_INT_CAST(UINT16, msg->xHot);
2507 pointerColor->hotSpotY = WINPR_ASSERTING_INT_CAST(UINT16, msg->yHot);
2508 pointerColor->width = WINPR_ASSERTING_INT_CAST(UINT16, msg->width);
2509 pointerColor->height = WINPR_ASSERTING_INT_CAST(UINT16, msg->height);
2510 pointerColor->lengthAndMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthAndMask);
2511 pointerColor->lengthXorMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthXorMask);
2512 pointerColor->xorMaskData = msg->xorMaskData;
2513 pointerColor->andMaskData = msg->andMaskData;
2514 pointerCached.cacheIndex = pointerColor->cacheIndex;
2516 if (client->activated)
2518 if (client->server->ShowMouseCursor)
2520 if (!IFCALLRESULT(TRUE, update->pointer->PointerNew, context, &pointerNew))
2522 if (!IFCALLRESULT(TRUE, update->pointer->PointerCached, context,
2529 pointer_system.type = SYSPTR_DEFAULT;
2530 if (!IFCALLRESULT(TRUE, update->pointer->PointerSystem, context,
2539 case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
2546 if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
2548 client->rdpsnd->src_format = msg->audio_format;
2551 IFCALLRESULT(CHANNEL_RC_OK, client->rdpsnd->SendSamples, client->rdpsnd,
2552 msg->buf, msg->nFrames, msg->wTimestamp);
2553 if (CHANNEL_RC_OK != error)
2560 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
2565 if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
2567 const UINT error = IFCALLRESULT(CHANNEL_RC_OK, client->rdpsnd->SetVolume,
2568 client->rdpsnd, msg->left, msg->right);
2569 if (CHANNEL_RC_OK != error)
2577 WLog_ERR(TAG,
"Unknown message id: %" PRIu32
"", message->id);
2581 shadow_client_free_queued_message(message);
2586static DWORD WINAPI shadow_client_thread(LPVOID arg)
2588 rdpShadowClient* client = (rdpShadowClient*)arg;
2591 wMessage message = WINPR_C_ARRAY_INIT;
2592 wMessage pointerPositionMsg = WINPR_C_ARRAY_INIT;
2593 wMessage pointerAlphaMsg = WINPR_C_ARRAY_INIT;
2594 wMessage audioVolumeMsg = WINPR_C_ARRAY_INIT;
2595 HANDLE ChannelEvent =
nullptr;
2596 void* UpdateSubscriber =
nullptr;
2597 HANDLE UpdateEvent =
nullptr;
2598 freerdp_peer* peer =
nullptr;
2599 rdpContext* context =
nullptr;
2600 rdpSettings* settings =
nullptr;
2601 rdpShadowServer* server =
nullptr;
2602 rdpShadowSubsystem* subsystem =
nullptr;
2603 wMessageQueue* MsgQueue =
nullptr;
2605 SHADOW_GFX_STATUS gfxstatus = WINPR_C_ARRAY_INIT;
2606 rdpUpdate* update =
nullptr;
2608 WINPR_ASSERT(client);
2610 MsgQueue = client->MsgQueue;
2611 WINPR_ASSERT(MsgQueue);
2613 server = client->server;
2614 WINPR_ASSERT(server);
2615 subsystem = server->subsystem;
2616 context = (rdpContext*)client;
2617 peer = context->peer;
2619 WINPR_ASSERT(peer->context);
2621 settings = peer->context->settings;
2622 WINPR_ASSERT(settings);
2624 peer->Capabilities = shadow_client_capabilities;
2625 peer->PostConnect = shadow_client_post_connect;
2626 peer->Activate = shadow_client_activate;
2627 peer->Logon = shadow_client_logon;
2628 shadow_input_register_callbacks(peer->context->input);
2630 rc = peer->Initialize(peer);
2634 update = peer->context->update;
2635 WINPR_ASSERT(update);
2637 update->RefreshRect = shadow_client_refresh_rect;
2638 update->SuppressOutput = shadow_client_suppress_output;
2639 update->SurfaceFrameAcknowledge = shadow_client_surface_frame_acknowledge;
2641 if ((!client->vcm) || (!subsystem->updateEvent))
2644 UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
2646 if (!UpdateSubscriber)
2649 UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
2650 WINPR_ASSERT(UpdateEvent);
2652 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
2653 WINPR_ASSERT(ChannelEvent);
2665 HANDLE events[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
2667 events[nCount++] = UpdateEvent;
2669 DWORD tmp = peer->GetEventHandles(peer, &events[nCount], 64 - nCount);
2673 WLog_ERR(TAG,
"Failed to get FreeRDP transport event handles");
2679 events[nCount++] = ChannelEvent;
2680 events[nCount++] = MessageQueue_Event(MsgQueue);
2682#if defined(CHANNEL_RDPGFX_SERVER)
2683 HANDLE gfxevent = rdpgfx_server_get_event_handle(client->rdpgfx);
2686 events[nCount++] = gfxevent;
2689 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
2691 if (status == WAIT_FAILED)
2694 if (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0)
2703 if (client->activated && !client->suppressOutput)
2708 if (shadow_client_recalc_desktop_size(client))
2711 if (!shadow_client_send_resize(client, &gfxstatus))
2713 WLog_ERR(TAG,
"Failed to send resize message");
2720 if (!shadow_client_send_surface_update(client, &gfxstatus))
2722 WLog_ERR(TAG,
"Failed to send surface update");
2730 if (!shadow_client_no_surface_update(client, &gfxstatus))
2732 WLog_ERR(TAG,
"Failed to handle surface update");
2741 (void)shadow_multiclient_consume(UpdateSubscriber);
2744 WINPR_ASSERT(peer->CheckFileDescriptor);
2745 if (!peer->CheckFileDescriptor(peer))
2747 WLog_ERR(TAG,
"Failed to check FreeRDP file descriptor");
2751 if (client->activated &&
2752 WTSVirtualChannelManagerIsChannelJoined(client->vcm, DRDYNVC_SVC_CHANNEL_NAME))
2754 switch (WTSVirtualChannelManagerGetDrdynvcState(client->vcm))
2757 case DRDYNVC_STATE_NONE:
2760 if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
2762 WLog_ERR(TAG,
"Failed to initialize drdynvc channel");
2768 case DRDYNVC_STATE_READY:
2769#if defined(CHANNEL_AUDIN_SERVER)
2770 if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
2772 if (!IFCALLRESULT(FALSE, client->audin->Open, client->audin))
2774 WLog_ERR(TAG,
"Failed to initialize audin channel");
2782 client->rdpgfx && !gfxstatus.gfxOpened)
2784 client->rdpgfx->FrameAcknowledge = shadow_client_rdpgfx_frame_acknowledge;
2785 client->rdpgfx->CapsAdvertise = shadow_client_rdpgfx_caps_advertise;
2787 if (!client->rdpgfx->Open(client->rdpgfx))
2789 WLog_WARN(TAG,
"Failed to open GraphicsPipeline");
2791 FreeRDP_SupportGraphicsPipeline, FALSE))
2796 gfxstatus.gfxOpened = TRUE;
2797 WLog_INFO(TAG,
"Gfx Pipeline Opened");
2808 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
2810 if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm))
2812 WLog_ERR(TAG,
"WTSVirtualChannelManagerCheckFileDescriptor failure");
2817#if defined(CHANNEL_RDPGFX_SERVER)
2820 if (WaitForSingleObject(gfxevent, 0) == WAIT_OBJECT_0)
2822 const UINT error = rdpgfx_server_handle_messages(client->rdpgfx);
2823 if (error != CHANNEL_RC_OK)
2829 if (WaitForSingleObject(MessageQueue_Event(MsgQueue), 0) == WAIT_OBJECT_0)
2832 pointerPositionMsg.id = 0;
2833 pointerPositionMsg.Free =
nullptr;
2834 pointerAlphaMsg.id = 0;
2835 pointerAlphaMsg.Free =
nullptr;
2836 audioVolumeMsg.id = 0;
2837 audioVolumeMsg.Free =
nullptr;
2839 while (MessageQueue_Peek(MsgQueue, &message, TRUE))
2841 if (message.id == WMQ_QUIT)
2848 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
2850 shadow_client_free_queued_message(&pointerPositionMsg);
2851 pointerPositionMsg = message;
2854 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
2856 shadow_client_free_queued_message(&pointerAlphaMsg);
2857 pointerAlphaMsg = message;
2860 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
2862 shadow_client_free_queued_message(&audioVolumeMsg);
2863 audioVolumeMsg = message;
2867 if (!shadow_client_subsystem_process_message(client, &message))
2873 if (message.id == WMQ_QUIT)
2876 shadow_client_free_queued_message(&pointerPositionMsg);
2877 shadow_client_free_queued_message(&pointerAlphaMsg);
2878 shadow_client_free_queued_message(&audioVolumeMsg);
2884 if (pointerPositionMsg.id)
2886 if (!shadow_client_subsystem_process_message(client, &pointerPositionMsg))
2890 if (pointerAlphaMsg.id)
2892 if (!shadow_client_subsystem_process_message(client, &pointerAlphaMsg))
2896 if (audioVolumeMsg.id)
2898 if (!shadow_client_subsystem_process_message(client, &audioVolumeMsg))
2908#if defined(CHANNEL_AUDIN_SERVER)
2909 if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
2911 if (!IFCALLRESULT(FALSE, client->audin->Close, client->audin))
2913 WLog_WARN(TAG,
"AUDIN shutdown failure!");
2918 if (gfxstatus.gfxOpened)
2920 if (gfxstatus.gfxSurfaceCreated)
2922 if (!shadow_client_rdpgfx_release_surface(client))
2923 WLog_WARN(TAG,
"GFX release surface failure!");
2926 WINPR_ASSERT(client->rdpgfx);
2927 WINPR_ASSERT(client->rdpgfx->Close);
2928 rc = client->rdpgfx->Close(client->rdpgfx);
2932 shadow_client_channels_free(client);
2934 if (UpdateSubscriber)
2936 shadow_multiclient_release_subscriber(UpdateSubscriber);
2937 UpdateSubscriber =
nullptr;
2940 if (peer->connected && subsystem->ClientDisconnect)
2942 subsystem->ClientDisconnect(subsystem, client);
2946 WINPR_ASSERT(peer->Disconnect);
2947 peer->Disconnect(peer);
2948 freerdp_peer_context_free(peer);
2949 freerdp_peer_free(peer);
2954BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
2956 rdpShadowClient* client =
nullptr;
2957 rdpShadowServer* server =
nullptr;
2959 if (!listener || !peer)
2962 server = (rdpShadowServer*)listener->info;
2963 WINPR_ASSERT(server);
2965 peer->ContextExtra = (
void*)server;
2966 peer->ContextSize =
sizeof(rdpShadowClient);
2967 peer->ContextNew = shadow_client_context_new;
2968 peer->ContextFree = shadow_client_context_free;
2970 if (!freerdp_peer_context_new_ex(peer, server->settings))
2973 client = (rdpShadowClient*)peer->context;
2974 WINPR_ASSERT(client);
2976 if (!(client->thread = CreateThread(
nullptr, 0, shadow_client_thread, client, 0,
nullptr)))
2978 freerdp_peer_context_free(peer);
2984 (void)CloseHandle(client->thread);
2985 client->thread =
nullptr;
2991static void shadow_msg_out_addref(wMessage* message)
2993 SHADOW_MSG_OUT* msg =
nullptr;
2995 WINPR_ASSERT(message);
2996 msg = (SHADOW_MSG_OUT*)message->wParam;
2999 InterlockedIncrement(&(msg->refCount));
3002static void shadow_msg_out_release(wMessage* message)
3004 SHADOW_MSG_OUT* msg =
nullptr;
3006 WINPR_ASSERT(message);
3007 msg = (SHADOW_MSG_OUT*)message->wParam;
3010 if (InterlockedDecrement(&(msg->refCount)) <= 0)
3012 IFCALL(msg->Free, message->id, msg);
3017static BOOL shadow_client_dispatch_msg(rdpShadowClient* client, wMessage* message)
3019 if (!client || !message)
3023 shadow_msg_out_addref(message);
3025 WINPR_ASSERT(client->MsgQueue);
3026 if (MessageQueue_Dispatch(client->MsgQueue, message))
3031 shadow_msg_out_release(message);
3036BOOL shadow_client_post_msg(rdpShadowClient* client,
void* context, UINT32 type,
3037 SHADOW_MSG_OUT* msg,
void* lParam)
3039 wMessage message = WINPR_C_ARRAY_INIT;
3040 message.context = context;
3042 message.wParam = (
void*)msg;
3043 message.lParam = lParam;
3044 message.Free = shadow_msg_out_release;
3045 return shadow_client_dispatch_msg(client, &message);
3048int shadow_client_boardcast_msg(rdpShadowServer* server,
void* context, UINT32 type,
3049 SHADOW_MSG_OUT* msg,
void* lParam)
3051 wMessage message = WINPR_C_ARRAY_INIT;
3054 WINPR_ASSERT(server);
3057 message.context = context;
3059 message.wParam = (
void*)msg;
3060 message.lParam = lParam;
3061 message.Free = shadow_msg_out_release;
3064 shadow_msg_out_addref(&message);
3066 WINPR_ASSERT(server->clients);
3067 ArrayList_Lock(server->clients);
3069 for (
size_t index = 0; index < ArrayList_Count(server->clients); index++)
3071 rdpShadowClient* client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
3073 if (shadow_client_dispatch_msg(client, &message))
3079 ArrayList_Unlock(server->clients);
3081 shadow_msg_out_release(&message);
3085int shadow_client_boardcast_quit(rdpShadowServer* server,
int nExitCode)
3087 wMessageQueue* queue =
nullptr;
3090 WINPR_ASSERT(server);
3091 WINPR_ASSERT(server->clients);
3093 ArrayList_Lock(server->clients);
3095 for (
size_t index = 0; index < ArrayList_Count(server->clients); index++)
3097 queue = ((rdpShadowClient*)ArrayList_GetItem(server->clients, index))->MsgQueue;
3099 if (MessageQueue_PostQuit(queue, nExitCode))
3105 ArrayList_Unlock(server->clients);
WINPR_ATTR_NODISCARD FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_bool(rdpSettings *settings, FreeRDP_Settings_Keys_Bool id, BOOL val)
Sets a BOOL settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_uint32(rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id, UINT32 val)
Sets a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_set_string(rdpSettings *settings, FreeRDP_Settings_Keys_String id, const char *val)
Sets a string settings value. The param is copied.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.
This struct contains function pointer to initialize/free objects.