FreeRDP
Loading...
Searching...
No Matches
shadow_client.c
1
21#include <freerdp/config.h>
22
23#include <winpr/crt.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>
32
33#include <freerdp/log.h>
34#include <freerdp/utils/gfx.h>
35#include <freerdp/channels/drdynvc.h>
36
37#include "shadow.h"
38#include "shadow_rfx_dirty.h"
39#include "shadow_autodetect.h"
40
41#define TAG CLIENT_TAG("shadow")
42
43#define SHADOW_CLIENT_MAX_INVALID_RECTS 256
44
45typedef struct
46{
47 BOOL gfxOpened;
48 BOOL gfxSurfaceCreated;
49} SHADOW_GFX_STATUS;
50
51WINPR_ATTR_NODISCARD
52static BOOL shadow_avc420_enabled(const rdpShadowClient* client);
53WINPR_ATTR_NODISCARD
54static BOOL shadow_avc444_enabled(const rdpShadowClient* client);
55
56/* See https://github.com/FreeRDP/FreeRDP/issues/10413
57 *
58 * Microsoft ditched support for RFX and multiple rectangles in BitmapUpdate for
59 * windows 11 24H2.
60 *
61 * So send all updates only with a single rectangle.
62 */
63#define BitmapUpdateProxy(client, bitmap) \
64 BitmapUpdateProxyEx((client), (bitmap), __FILE__, __LINE__, __func__)
65WINPR_ATTR_NODISCARD
66static BOOL BitmapUpdateProxyEx(rdpShadowClient* client, const BITMAP_UPDATE* bitmap,
67 const char* file, size_t line, const char* fkt)
68{
69 WINPR_ASSERT(client);
70 WINPR_ASSERT(bitmap);
71
72 rdpShadowServer* server = client->server;
73 WINPR_ASSERT(server);
74
75 rdpContext* context = (rdpContext*)client;
76
77 rdpUpdate* update = context->update;
78 WINPR_ASSERT(update);
79
80 if (server->SupportMultiRectBitmapUpdates)
81 {
82 const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, bitmap);
83 if (!rc)
84 {
85 const DWORD log_level = WLOG_ERROR;
86 wLog* log = WLog_Get(TAG);
87 if (WLog_IsLevelActive(log, log_level))
88 {
89 WLog_PrintTextMessage(log, log_level, line, file, fkt,
90 "BitmapUpdate[count %" PRIu32 "] failed", bitmap->number);
91 }
92 return FALSE;
93 }
94 }
95 else
96 {
97 for (UINT32 x = 0; x < bitmap->number; x++)
98 {
99 BITMAP_UPDATE cur = WINPR_C_ARRAY_INIT;
100 BITMAP_DATA* bmp = &bitmap->rectangles[x];
101 cur.rectangles = bmp;
102 cur.number = 1;
103 cur.skipCompression = bitmap->skipCompression;
104 const BOOL rc = IFCALLRESULT(FALSE, update->BitmapUpdate, context, &cur);
105 if (!rc)
106 {
107 const DWORD log_level = WLOG_ERROR;
108 wLog* log = WLog_Get(TAG);
109 if (WLog_IsLevelActive(log, log_level))
110 {
111 WLog_PrintTextMessage(log, log_level, line, file, fkt,
112 "BitmapUpdate[count 1, at %" PRIu32 "] failed", x);
113 }
114 return FALSE;
115 }
116 }
117 }
118
119 return TRUE;
120}
121
122WINPR_ATTR_NODISCARD
123static inline BOOL shadow_client_rdpgfx_new_surface(rdpShadowClient* client)
124{
125 UINT error = CHANNEL_RC_OK;
126 RDPGFX_CREATE_SURFACE_PDU createSurface;
127 RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU surfaceToOutput;
128 RdpgfxServerContext* context = nullptr;
129 rdpSettings* settings = nullptr;
130
131 WINPR_ASSERT(client);
132 context = client->rdpgfx;
133 WINPR_ASSERT(context);
134 settings = ((rdpContext*)client)->settings;
135 WINPR_ASSERT(settings);
136
137 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
138 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
139 createSurface.width = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
140 createSurface.height = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
141 createSurface.pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
142 createSurface.surfaceId = client->surfaceId;
143 surfaceToOutput.outputOriginX = 0;
144 surfaceToOutput.outputOriginY = 0;
145 surfaceToOutput.surfaceId = client->surfaceId;
146 surfaceToOutput.reserved = 0;
147 IFCALLRET(context->CreateSurface, error, context, &createSurface);
148
149 if (error)
150 {
151 WLog_ERR(TAG, "CreateSurface failed with error %" PRIu32 "", error);
152 return FALSE;
153 }
154
155 IFCALLRET(context->MapSurfaceToOutput, error, context, &surfaceToOutput);
156
157 if (error)
158 {
159 WLog_ERR(TAG, "MapSurfaceToOutput failed with error %" PRIu32 "", error);
160 return FALSE;
161 }
162
163 return TRUE;
164}
165
166WINPR_ATTR_NODISCARD
167static inline BOOL shadow_client_rdpgfx_release_surface(rdpShadowClient* client)
168{
169 UINT error = CHANNEL_RC_OK;
171 RdpgfxServerContext* context = nullptr;
172
173 WINPR_ASSERT(client);
174
175 context = client->rdpgfx;
176 WINPR_ASSERT(context);
177
178 pdu.surfaceId = client->surfaceId++;
179 IFCALLRET(context->DeleteSurface, error, context, &pdu);
180
181 if (error)
182 {
183 WLog_ERR(TAG, "DeleteSurface failed with error %" PRIu32 "", error);
184 return FALSE;
185 }
186
187 return TRUE;
188}
189
190WINPR_ATTR_NODISCARD
191static inline BOOL shadow_client_rdpgfx_reset_graphic(rdpShadowClient* client)
192{
193 UINT error = CHANNEL_RC_OK;
194 RDPGFX_RESET_GRAPHICS_PDU pdu = WINPR_C_ARRAY_INIT;
195 RdpgfxServerContext* context = nullptr;
196 rdpSettings* settings = nullptr;
197
198 WINPR_ASSERT(client);
199 WINPR_ASSERT(client->rdpgfx);
200
201 context = client->rdpgfx;
202 WINPR_ASSERT(context);
203
204 settings = client->context.settings;
205 WINPR_ASSERT(settings);
206
207 pdu.width = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
208 pdu.height = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
209 pdu.monitorCount = client->subsystem->numMonitors;
210 pdu.monitorDefArray = client->subsystem->monitors;
211 IFCALLRET(context->ResetGraphics, error, context, &pdu);
212
213 if (error)
214 {
215 WLog_ERR(TAG, "ResetGraphics failed with error %" PRIu32 "", error);
216 return FALSE;
217 }
218
219 client->first_frame = TRUE;
220 return TRUE;
221}
222
223static inline void shadow_client_free_queued_message(void* obj)
224{
225 wMessage* message = (wMessage*)obj;
226
227 WINPR_ASSERT(message);
228 if (message->Free)
229 {
230 message->Free(message);
231 message->Free = nullptr;
232 }
233}
234
235static void shadow_client_context_free(freerdp_peer* peer, rdpContext* context)
236{
237 rdpShadowClient* client = (rdpShadowClient*)context;
238 rdpShadowServer* server = nullptr;
239
240 WINPR_UNUSED(peer);
241 if (!client)
242 return;
243
244 server = client->server;
245 if (server && server->clients)
246 ArrayList_Remove(server->clients, (void*)client);
247
248 shadow_client_autodetect_uninit(client);
249 shadow_encoder_free(client->encoder);
250
251 /* Clear queued messages and free resource */
252 MessageQueue_Free(client->MsgQueue);
253 MessageQueue_Free(client->SoundQueue);
254 WTSCloseServer(client->vcm);
255 region16_uninit(&(client->invalidRegion));
256 DeleteCriticalSection(&(client->vcmLock));
257 DeleteCriticalSection(&(client->lock));
258
259 client->MsgQueue = nullptr;
260 client->SoundQueue = nullptr;
261 client->encoder = nullptr;
262 client->vcm = nullptr;
263}
264
265WINPR_ATTR_NODISCARD
266static BOOL shadow_client_context_new(freerdp_peer* peer, rdpContext* context)
267{
268 BOOL NSCodec = 0;
269 const char bind_address[] = "bind-address,";
270 rdpShadowClient* client = (rdpShadowClient*)context;
271 rdpSettings* settings = nullptr;
272 const rdpSettings* srvSettings = nullptr;
273 rdpShadowServer* server = nullptr;
274 const wObject cb = { nullptr, nullptr, nullptr, shadow_client_free_queued_message, nullptr };
275
276 WINPR_ASSERT(client);
277 WINPR_ASSERT(peer);
278 WINPR_ASSERT(peer->context);
279
280 server = (rdpShadowServer*)peer->ContextExtra;
281 WINPR_ASSERT(server);
282
283 srvSettings = server->settings;
284 WINPR_ASSERT(srvSettings);
285
286 client->surfaceId = 1;
287 client->server = server;
288 client->subsystem = server->subsystem;
289 WINPR_ASSERT(client->subsystem);
290
291 settings = peer->context->settings;
292 WINPR_ASSERT(settings);
293
294 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth,
295 freerdp_settings_get_uint32(srvSettings, FreeRDP_ColorDepth)))
296 return FALSE;
297 NSCodec = freerdp_settings_get_bool(srvSettings, FreeRDP_NSCodec);
298 if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, NSCodec))
299 return FALSE;
300 if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec,
301 freerdp_settings_get_bool(srvSettings, FreeRDP_RemoteFxCodec)))
302 return FALSE;
304 settings, FreeRDP_RemoteFxRlgrMode,
305 freerdp_settings_get_uint32(srvSettings, FreeRDP_RemoteFxRlgrMode)))
306 return FALSE;
307 if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheV3Enabled, TRUE))
308 return FALSE;
309 if (!freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE))
310 return FALSE;
311 if (!freerdp_settings_set_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE))
312 return FALSE;
314 settings, FreeRDP_SupportGraphicsPipeline,
315 freerdp_settings_get_bool(srvSettings, FreeRDP_SupportGraphicsPipeline)))
316 return FALSE;
317 if (!freerdp_settings_set_bool(settings, FreeRDP_GfxH264,
318 freerdp_settings_get_bool(srvSettings, FreeRDP_GfxH264)))
319 return FALSE;
320 if (!freerdp_settings_set_bool(settings, FreeRDP_DrawAllowSkipAlpha, TRUE))
321 return FALSE;
322 if (!freerdp_settings_set_bool(settings, FreeRDP_DrawAllowColorSubsampling, TRUE))
323 return FALSE;
324 if (!freerdp_settings_set_bool(settings, FreeRDP_DrawAllowDynamicColorFidelity, TRUE))
325 return FALSE;
326 if (!freerdp_settings_set_uint32(settings, FreeRDP_CompressionLevel, PACKET_COMPR_TYPE_RDP8))
327 return FALSE;
328
329 if (server->ipcSocket && (strncmp(bind_address, server->ipcSocket,
330 strnlen(bind_address, sizeof(bind_address))) != 0))
331 {
332 if (!freerdp_settings_set_bool(settings, FreeRDP_LyncRdpMode, TRUE))
333 return FALSE;
334 if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, FALSE))
335 return FALSE;
336 }
337
338 client->inLobby = TRUE;
339 client->mayView = server->mayView;
340 client->mayInteract = server->mayInteract;
341
342 if (!InitializeCriticalSectionAndSpinCount(&(client->lock), 4000))
343 goto fail;
344
345 if (!InitializeCriticalSectionAndSpinCount(&(client->vcmLock), 4000))
346 goto fail;
347
348 region16_init(&(client->invalidRegion));
349 client->vcm = WTSOpenServerA((LPSTR)peer->context);
350
351 if (!client->vcm || client->vcm == INVALID_HANDLE_VALUE)
352 goto fail;
353
354 if (!(client->MsgQueue = MessageQueue_New(&cb)))
355 goto fail;
356
357 if (!(client->SoundQueue = MessageQueue_New(&cb)))
358 goto fail;
359
360 if (!(client->encoder = shadow_encoder_new(client)))
361 goto fail;
362
363 if (!shadow_client_autodetect_init(client))
364 goto fail;
365
366 if (!ArrayList_Append(server->clients, (void*)client))
367 goto fail;
368
369 return TRUE;
370
371fail:
372 shadow_client_context_free(peer, context);
373 return FALSE;
374}
375
388WINPR_ATTR_NODISCARD
389static BOOL shadow_client_invalidate_rect(rdpShadowClient* client, const RECTANGLE_16* rect)
390{
391 WINPR_ASSERT(client);
392
393 REGION16* region = &(client->invalidRegion);
394 if (!region16_union_rect(region, region, rect))
395 return FALSE;
396
397 if (region16_n_rects(region) <= SHADOW_CLIENT_MAX_INVALID_RECTS)
398 return TRUE;
399
400 const RECTANGLE_16 extents = *region16_extents(region);
401 region16_clear(region);
402 return region16_union_rect(region, region, &extents);
403}
404
405static inline void shadow_client_mark_invalid(rdpShadowClient* client, UINT32 numRects,
406 const RECTANGLE_16* rects)
407{
408 WINPR_ASSERT(client);
409 WINPR_ASSERT(rects || (numRects == 0));
410
411 rdpSettings* settings = client->context.settings;
412 WINPR_ASSERT(settings);
413
414 EnterCriticalSection(&(client->lock));
415
416 /* Mark client invalid region. No rectangle means full screen */
417 if (numRects > 0)
418 {
419 for (UINT32 index = 0; index < numRects; index++)
420 {
421 if (!shadow_client_invalidate_rect(client, &rects[index]))
422 goto fail;
423 }
424 }
425 else
426 {
427 RECTANGLE_16 screenRegion = WINPR_C_ARRAY_INIT;
428 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
429 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
430 screenRegion.right = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
431 screenRegion.bottom = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
432 if (!shadow_client_invalidate_rect(client, &screenRegion))
433 goto fail;
434 }
435fail:
436 LeaveCriticalSection(&(client->lock));
437}
438
445WINPR_ATTR_NODISCARD
446static inline BOOL shadow_client_recalc_desktop_size(rdpShadowClient* client)
447{
448 INT32 width = 0;
449 INT32 height = 0;
450 rdpShadowServer* server = nullptr;
451 rdpSettings* settings = nullptr;
452 RECTANGLE_16 viewport = WINPR_C_ARRAY_INIT;
453
454 WINPR_ASSERT(client);
455 server = client->server;
456 settings = client->context.settings;
457
458 WINPR_ASSERT(server);
459 WINPR_ASSERT(server->surface);
460 WINPR_ASSERT(settings);
461
462 WINPR_ASSERT(server->surface->width <= UINT16_MAX);
463 WINPR_ASSERT(server->surface->height <= UINT16_MAX);
464 viewport.right = (UINT16)server->surface->width;
465 viewport.bottom = (UINT16)server->surface->height;
466
467 if (server->shareSubRect)
468 {
469 if (!rectangles_intersection(&viewport, &(server->subRect), &viewport))
470 return FALSE;
471 }
472
473 width = viewport.right - viewport.left;
474 height = viewport.bottom - viewport.top;
475
476 WINPR_ASSERT(width >= 0);
477 WINPR_ASSERT(width <= UINT16_MAX);
478 WINPR_ASSERT(height >= 0);
479 WINPR_ASSERT(height <= UINT16_MAX);
480 return (freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) != (UINT32)width ||
481 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) != (UINT32)height);
482}
483
484WINPR_ATTR_NODISCARD
485static BOOL shadow_client_capabilities(freerdp_peer* peer)
486{
487 rdpShadowSubsystem* subsystem = nullptr;
488 rdpShadowClient* client = nullptr;
489 BOOL ret = TRUE;
490
491 WINPR_ASSERT(peer);
492
493 client = (rdpShadowClient*)peer->context;
494 WINPR_ASSERT(client);
495 WINPR_ASSERT(client->server);
496
497 subsystem = client->server->subsystem;
498 WINPR_ASSERT(subsystem);
499
500 IFCALLRET(subsystem->ClientCapabilities, ret, subsystem, client);
501
502 if (!ret)
503 WLog_WARN(TAG, "subsystem->ClientCapabilities failed");
504
505 return ret;
506}
507
508static void shadow_reset_desktop_resize(rdpShadowClient* client)
509{
510 WINPR_ASSERT(client);
511 client->resizeRequested = FALSE;
512}
513
514WINPR_ATTR_NODISCARD
515static BOOL shadow_send_desktop_resize(rdpShadowClient* client)
516{
517 BOOL rc = 0;
518 rdpUpdate* update = nullptr;
519 rdpSettings* settings = nullptr;
520 const freerdp_peer* peer = nullptr;
521
522 WINPR_ASSERT(client);
523
524 settings = client->context.settings;
525 peer = client->context.peer;
526 WINPR_ASSERT(peer);
527 WINPR_ASSERT(client->server);
528 WINPR_ASSERT(client->server->surface);
529
530 const UINT32 resizeWidth = client->server->surface->width;
531 const UINT32 resizeHeight = client->server->surface->height;
532
533 if (client->resizeRequested)
534 {
535 if ((resizeWidth == client->resizeWidth) && (resizeHeight == client->resizeHeight))
536 {
537 const UINT32 w = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
538 const UINT32 h = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
539 WLog_WARN(TAG,
540 "detected previous resize request for resolution %" PRIu32 "x%" PRIu32
541 ", still have %" PRIu32 "x%" PRIu32 ", disconnecting peer",
542 resizeWidth, resizeHeight, w, h);
543 return FALSE;
544 }
545 }
546
547 update = client->context.update;
548 WINPR_ASSERT(update);
549 WINPR_ASSERT(update->DesktopResize);
550
551 // Update peer resolution, required so that during disconnect/reconnect the correct resolution
552 // is sent to the client.
553 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, resizeWidth))
554 return FALSE;
555 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, resizeHeight))
556 return FALSE;
557 rc = update->DesktopResize(update->context);
558 WLog_INFO(TAG, "Client %s resize requested (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
559 peer->hostname, resizeWidth, resizeHeight,
560 freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth));
561 client->resizeRequested = TRUE;
562 client->resizeWidth = resizeWidth;
563 client->resizeHeight = resizeHeight;
564
565 return rc;
566}
567
568WINPR_ATTR_NODISCARD
569static BOOL shadow_client_post_connect(freerdp_peer* peer)
570{
571 int authStatus = 0;
572 rdpSettings* settings = nullptr;
573 rdpShadowClient* client = nullptr;
574 rdpShadowServer* server = nullptr;
575 rdpShadowSubsystem* subsystem = nullptr;
576
577 WINPR_ASSERT(peer);
578
579 client = (rdpShadowClient*)peer->context;
580 WINPR_ASSERT(client);
581
582 settings = peer->context->settings;
583 WINPR_ASSERT(settings);
584
585 server = client->server;
586 WINPR_ASSERT(server);
587
588 subsystem = server->subsystem;
589 WINPR_ASSERT(subsystem);
590
591 if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) == 24)
592 {
593 if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 16)) /* disable 24bpp */
594 return FALSE;
595 }
596
597 const UINT32 MultifragMaxRequestSize =
598 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize);
599 if (MultifragMaxRequestSize < 0x3F0000)
600 {
602 settings, FreeRDP_NSCodec,
603 FALSE); /* NSCodec compressor does not support fragmentation yet */
604 if (!rc)
605 return FALSE;
606 }
607
608 WLog_INFO(TAG, "Client from %s is activated (%" PRIu32 "x%" PRIu32 "@%" PRIu32 ")",
609 peer->hostname, freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
610 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
611 freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth));
612
613 if (shadow_client_channels_post_connect(client) != CHANNEL_RC_OK)
614 return FALSE;
615
616 shadow_client_mark_invalid(client, 0, nullptr);
617 authStatus = -1;
618
619 const char* Username = freerdp_settings_get_string(settings, FreeRDP_Username);
620 const char* Domain = freerdp_settings_get_string(settings, FreeRDP_Domain);
621 const char* Password = freerdp_settings_get_string(settings, FreeRDP_Password);
622
623 if (Username && Password)
624 {
625 if (!freerdp_settings_set_bool(settings, FreeRDP_AutoLogonEnabled, TRUE))
626 return FALSE;
627 }
628
629 if (server->authentication && !(freerdp_settings_get_bool(settings, FreeRDP_NlaSecurity) ||
630 freerdp_settings_get_bool(settings, FreeRDP_ExtSecurity)))
631 {
632 if (subsystem->Authenticate)
633 {
634 authStatus = subsystem->Authenticate(subsystem, client, Username, Domain, Password);
635 }
636
637 if (authStatus < 0)
638 {
639 WLog_ERR(TAG, "client authentication failure: %d", authStatus);
640 /* Say why before the connection goes, or the client takes it for a network
641 * failure and keeps reconnecting with the same wrong password. */
642 freerdp_set_error_info(peer->context->rdp, ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES);
643 WINPR_ASSERT(peer->Close);
644 if (!peer->Close(peer))
645 WLog_WARN(TAG, "failed to send the disconnect sequence to the client");
646 return FALSE;
647 }
648 }
649
650 if (subsystem->ClientConnect)
651 {
652 return subsystem->ClientConnect(subsystem, client);
653 }
654
655 return TRUE;
656}
657
658/* Convert rects in sub rect coordinate to client/surface coordinate */
659static inline void shadow_client_convert_rects(rdpShadowClient* client, RECTANGLE_16* dst,
660 const RECTANGLE_16* src, UINT32 numRects)
661{
662 WINPR_ASSERT(client);
663 WINPR_ASSERT(client->server);
664 WINPR_ASSERT(dst);
665 WINPR_ASSERT(src || (numRects == 0));
666
667 if (client->server->shareSubRect)
668 {
669 UINT16 offsetX = client->server->subRect.left;
670 UINT16 offsetY = client->server->subRect.top;
671
672 for (UINT32 i = 0; i < numRects; i++)
673 {
674 const RECTANGLE_16* s = &src[i];
675 RECTANGLE_16* d = &dst[i];
676
677 d->left = s->left + offsetX;
678 d->right = s->right + offsetX;
679 d->top = s->top + offsetY;
680 d->bottom = s->bottom + offsetY;
681 }
682 }
683 else
684 {
685 if (src != dst)
686 {
687 CopyMemory(dst, src, numRects * sizeof(RECTANGLE_16));
688 }
689 }
690}
691
692WINPR_ATTR_NODISCARD
693static BOOL shadow_client_refresh_request(rdpShadowClient* client)
694{
695 wMessage message = WINPR_C_ARRAY_INIT;
696 wMessagePipe* MsgPipe = nullptr;
697
698 WINPR_ASSERT(client);
699 WINPR_ASSERT(client->subsystem);
700
701 MsgPipe = client->subsystem->MsgPipe;
702 WINPR_ASSERT(MsgPipe);
703
704 message.id = SHADOW_MSG_IN_REFRESH_REQUEST_ID;
705 message.wParam = nullptr;
706 message.lParam = nullptr;
707 message.context = (void*)client;
708 message.Free = nullptr;
709 return MessageQueue_Dispatch(MsgPipe->In, &message);
710}
711
712WINPR_ATTR_NODISCARD
713static BOOL shadow_client_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
714{
715 rdpShadowClient* client = (rdpShadowClient*)context;
716 RECTANGLE_16* rects = nullptr;
717
718 /* It is invalid if we have area count but no actual area */
719 if (count && !areas)
720 return FALSE;
721
722 if (count)
723 {
724 rects = (RECTANGLE_16*)calloc(count, sizeof(RECTANGLE_16));
725
726 if (!rects)
727 {
728 return FALSE;
729 }
730
731 shadow_client_convert_rects(client, rects, areas, count);
732 shadow_client_mark_invalid(client, count, rects);
733 free(rects);
734 }
735 else
736 {
737 shadow_client_mark_invalid(client, 0, nullptr);
738 }
739
740 return shadow_client_refresh_request(client);
741}
742
743WINPR_ATTR_NODISCARD
744static BOOL shadow_client_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
745{
746 rdpShadowClient* client = (rdpShadowClient*)context;
747 RECTANGLE_16 region;
748
749 WINPR_ASSERT(client);
750
751 client->suppressOutput = !(allow);
752
753 if (allow)
754 {
755 if (area)
756 {
757 shadow_client_convert_rects(client, &region, area, 1);
758 shadow_client_mark_invalid(client, 1, &region);
759 }
760 else
761 {
762 shadow_client_mark_invalid(client, 0, nullptr);
763 }
764 }
765
766 return shadow_client_refresh_request(client);
767}
768
769WINPR_ATTR_NODISCARD
770static BOOL shadow_client_activate(freerdp_peer* peer)
771{
772 WINPR_ASSERT(peer);
773
774 rdpShadowClient* client = (rdpShadowClient*)peer->context;
775 WINPR_ASSERT(client);
776
777 /* Resize client if necessary */
778 if (shadow_client_recalc_desktop_size(client))
779 return shadow_send_desktop_resize(client);
780
781 shadow_reset_desktop_resize(client);
782 client->activated = TRUE;
783 client->inLobby = !(client->mayView);
784
785 if (shadow_encoder_reset(client->encoder) < 0)
786 {
787 WLog_ERR(TAG, "Failed to reset encoder");
788 return FALSE;
789 }
790
791 /* Update full screen in next update */
792 return shadow_client_refresh_rect(&client->context, 0, nullptr);
793}
794
795WINPR_ATTR_NODISCARD
796static BOOL shadow_client_logon(freerdp_peer* peer, const SEC_WINNT_AUTH_IDENTITY* identity,
797 BOOL automatic)
798{
799 BOOL rc = FALSE;
800 char* user = nullptr;
801 char* domain = nullptr;
802 char* password = nullptr;
803 rdpSettings* settings = nullptr;
804
805 WINPR_UNUSED(automatic);
806
807 WINPR_ASSERT(peer);
808 WINPR_ASSERT(identity);
809
810 WINPR_ASSERT(peer->context);
811
812 settings = peer->context->settings;
813 WINPR_ASSERT(settings);
814
815 if (identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE)
816 {
817 if (identity->User)
818 user = ConvertWCharNToUtf8Alloc(identity->User, identity->UserLength, nullptr);
819
820 if (identity->Domain)
821 domain = ConvertWCharNToUtf8Alloc(identity->Domain, identity->DomainLength, nullptr);
822
823 if (identity->Password)
824 password =
825 ConvertWCharNToUtf8Alloc(identity->Password, identity->PasswordLength, nullptr);
826 }
827 else
828 {
829 if (identity->User)
830 user = _strdup((char*)identity->User);
831
832 if (identity->Domain)
833 domain = _strdup((char*)identity->Domain);
834
835 if (identity->Password)
836 password = _strdup((char*)identity->Password);
837 }
838
839 if ((identity->User && !user) || (identity->Domain && !domain) ||
840 (identity->Password && !password))
841 goto fail;
842
843 if (user)
844 {
845 if (!freerdp_settings_set_string(settings, FreeRDP_Username, user))
846 goto fail;
847 }
848
849 if (domain)
850 {
851 if (!freerdp_settings_set_string(settings, FreeRDP_Domain, domain))
852 goto fail;
853 }
854 if (password)
855 {
856 if (!freerdp_settings_set_string(settings, FreeRDP_Password, password))
857 goto fail;
858 }
859 rc = TRUE;
860fail:
861 free(user);
862 free(domain);
863 free(password);
864 return rc;
865}
866
867static inline void shadow_client_common_frame_acknowledge(rdpShadowClient* client, UINT32 frameId)
868{
869 /*
870 * Record the last client acknowledged frame id to
871 * calculate how much frames are in progress.
872 * Some rdp clients (win7 mstsc) skips frame ACK if it is
873 * inactive, we should not expect ACK for each frame.
874 * So it is OK to calculate in-flight frame count according to
875 * a latest acknowledged frame id.
876 */
877 WINPR_ASSERT(client);
878 WINPR_ASSERT(client->encoder);
879 client->encoder->lastAckframeId = frameId;
880 client->encoder->lastAckTick = GetTickCount64();
881 client->encoder->everAcked = TRUE;
882}
883
884WINPR_ATTR_NODISCARD
885static BOOL shadow_client_surface_frame_acknowledge(rdpContext* context, UINT32 frameId)
886{
887 rdpShadowClient* client = (rdpShadowClient*)context;
888 shadow_client_common_frame_acknowledge(client, frameId);
889 /*
890 * Reset queueDepth for legacy none RDPGFX acknowledge
891 */
892 WINPR_ASSERT(client);
893 WINPR_ASSERT(client->encoder);
894 client->encoder->queueDepth = QUEUE_DEPTH_UNAVAILABLE;
895 return TRUE;
896}
897
898WINPR_ATTR_NODISCARD
899static UINT
900shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context,
901 const RDPGFX_FRAME_ACKNOWLEDGE_PDU* frameAcknowledge)
902{
903 rdpShadowClient* client = nullptr;
904
905 WINPR_ASSERT(context);
906 WINPR_ASSERT(frameAcknowledge);
907
908 client = (rdpShadowClient*)context->custom;
909 shadow_client_common_frame_acknowledge(client, frameAcknowledge->frameId);
910
911 WINPR_ASSERT(client);
912 WINPR_ASSERT(client->encoder);
913 client->encoder->queueDepth = frameAcknowledge->queueDepth;
914 return CHANNEL_RC_OK;
915}
916
917WINPR_ATTR_NODISCARD
918static BOOL shadow_are_caps_filtered(const rdpSettings* settings, UINT32 caps)
919{
920 const UINT32 capList[] = {
921#if defined(WITH_GFX_AV1)
922 RDPGFX_CAPVERSION_FRDP_1,
923#endif
924#if defined(WITH_GFX_AV2)
925 RDPGFX_CAPVERSION_FRDP_2,
926#endif
927 RDPGFX_CAPVERSION_8,
928 RDPGFX_CAPVERSION_81,
929 RDPGFX_CAPVERSION_10,
930 RDPGFX_CAPVERSION_101,
931 RDPGFX_CAPVERSION_102,
932 RDPGFX_CAPVERSION_103,
933 RDPGFX_CAPVERSION_104,
934 RDPGFX_CAPVERSION_105,
935 RDPGFX_CAPVERSION_106,
936 RDPGFX_CAPVERSION_106_ERR,
937 RDPGFX_CAPVERSION_107
938#if defined(WITH_GFX_AZURE)
939 ,
940 RDPGFX_CAPVERSION_111,
941 RDPGFX_CAPVERSION_112,
942 RDPGFX_CAPVERSION_113,
943 RDPGFX_CAPVERSION_115
944#endif
945 };
946
947 WINPR_ASSERT(settings);
948 const UINT32 filter = freerdp_settings_get_uint32(settings, FreeRDP_GfxCapsFilter);
949
950 for (UINT32 x = 0; x < ARRAYSIZE(capList); x++)
951 {
952 if (caps == capList[x])
953 return (filter & (1u << x)) != 0;
954 }
955
956 return TRUE;
957}
958
959/* The 8.1 capability set turns AVC420 on with a flag; from 10.0 on AVC420 is part of the set
960 * unless the AVC codecs are disabled (the 8.1 flag is not defined there, so a 10.x client never
961 * sets it). */
962WINPR_ATTR_NODISCARD
963static BOOL shadow_client_caps_allow_avc420(const RDPGFX_CAPSET* caps)
964{
965 WINPR_ASSERT(caps);
966 if (caps->version == RDPGFX_CAPVERSION_81)
967 return (caps->flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED) != 0;
968 return (caps->flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0;
969}
970
971WINPR_ATTR_NODISCARD
972static UINT shadow_client_send_caps_confirm(RdpgfxServerContext* context, rdpShadowClient* client,
973 const RDPGFX_CAPS_CONFIRM_PDU* pdu)
974{
975 WINPR_ASSERT(context);
976 WINPR_ASSERT(client);
977 WINPR_ASSERT(pdu);
978
979 WINPR_ASSERT(context->CapsConfirm);
980 UINT rc = context->CapsConfirm(context, pdu);
981 client->areGfxCapsReady = (rc == CHANNEL_RC_OK);
982 client->confirmedCaps = *pdu->capsSet;
983
984 rdpSettings* clientSettings = client->context.settings;
985 WINPR_ASSERT(clientSettings);
986
987#if defined(WITH_GFX_AV2)
988 if (pdu->capsSet->version == RDPGFX_CAPVERSION_FRDP_2)
989 {
990 UINT32 flags = FREERDP_CODEC_AV2_I420;
991 if ((pdu->capsSet->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) == 0)
992 flags = FREERDP_CODEC_AV2_I444;
993
994 if (shadow_encoder_prepare(client->encoder, flags) < 0)
995 return ERROR_INVALID_PARAMETER;
996 }
997 else
998#endif
999#if defined(WITH_GFX_AV1)
1000 if (pdu->capsSet->version == RDPGFX_CAPVERSION_FRDP_1)
1001 {
1002 UINT32 flags = FREERDP_CODEC_AV1_I420;
1003 if ((pdu->capsSet->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) == 0)
1004 flags = FREERDP_CODEC_AV1_I444;
1005
1006 if (shadow_encoder_prepare(client->encoder, flags) < 0)
1007 return ERROR_INVALID_PARAMETER;
1008 }
1009 else
1010#endif
1011 if (shadow_avc444_enabled(client) || shadow_avc420_enabled(client))
1012 {
1013#ifdef WITH_GFX_H264
1014 const BOOL h264 = (shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 |
1015 FREERDP_CODEC_AVC444) >= 0);
1016 if (h264)
1017 {
1018 /* the server's own setting (-gfx-avc420) still counts */
1020 clientSettings, FreeRDP_GfxH264,
1021 shadow_client_caps_allow_avc420(pdu->capsSet) &&
1022 freerdp_settings_get_bool(clientSettings, FreeRDP_GfxH264)))
1023 return rc;
1024 }
1025 else
1026 {
1027 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
1028 return rc;
1029 }
1030#else
1031 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE))
1032 return rc;
1033 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE))
1034 return rc;
1035 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
1036 return rc;
1037#endif
1038 }
1039
1040 return rc;
1041}
1042
1043WINPR_ATTR_NODISCARD
1044static BOOL shadow_client_caps_test_version(RdpgfxServerContext* context, rdpShadowClient* client,
1045 BOOL h264, const RDPGFX_CAPSET* capsSets,
1046 UINT32 capsSetCount, UINT32 capsVersion, UINT* rc)
1047{
1048 WINPR_ASSERT(context);
1049 WINPR_ASSERT(client);
1050 WINPR_ASSERT(capsSets || (capsSetCount == 0));
1051 WINPR_ASSERT(rc);
1052
1053 WINPR_ASSERT(context->rdpcontext);
1054 const rdpSettings* srvSettings = context->rdpcontext->settings;
1055 WINPR_ASSERT(srvSettings);
1056
1057 rdpSettings* clientSettings = client->context.settings;
1058 WINPR_ASSERT(clientSettings);
1059
1060 if (shadow_are_caps_filtered(srvSettings, capsVersion))
1061 return FALSE;
1062
1063 for (UINT32 index = 0; index < capsSetCount; index++)
1064 {
1065 const RDPGFX_CAPSET* currentCaps = &capsSets[index];
1066
1067 WLog_INFO(TAG, "testing %s vs %s[0x%08" PRIx32 "]",
1068 rdpgfx_caps_version_str(currentCaps->version),
1069 rdpgfx_caps_version_str(capsVersion), capsVersion);
1070 if (currentCaps->version == capsVersion)
1071 {
1072 RDPGFX_CAPSET caps = *currentCaps;
1073 RDPGFX_CAPS_CONFIRM_PDU pdu = WINPR_C_ARRAY_INIT;
1074 pdu.capsSet = &caps;
1075
1076 const UINT32 flags = pdu.capsSet->flags;
1077
1078 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache,
1079 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1080 return FALSE;
1081
1082 BOOL avc420 = TRUE;
1083 BOOL avc444 = !(flags & RDPGFX_CAPS_FLAG_AVC_DISABLED);
1084 BOOL avc444v2 = avc444;
1085 if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxAVC444v2) || !h264)
1086 avc444v2 = FALSE;
1087 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, avc444v2))
1088 return FALSE;
1089 if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxAVC444) || !h264)
1090 avc444 = FALSE;
1091 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, avc444))
1092 return FALSE;
1093 if (!freerdp_settings_get_bool(srvSettings, FreeRDP_GfxH264) || !h264)
1094 avc420 = FALSE;
1095 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, avc420))
1096 return FALSE;
1097
1098 const BOOL progressive = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxProgressive);
1099 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxProgressive, progressive))
1100 return FALSE;
1101 const BOOL progressivev2 =
1102 freerdp_settings_get_bool(srvSettings, FreeRDP_GfxProgressiveV2);
1103 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxProgressiveV2, progressivev2))
1104 return FALSE;
1105
1106 const BOOL rfx = freerdp_settings_get_bool(srvSettings, FreeRDP_RemoteFxCodec);
1107 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_RemoteFxCodec, rfx))
1108 return FALSE;
1109
1110 const BOOL planar = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxPlanar);
1111 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxPlanar, planar))
1112 return FALSE;
1113#if defined(WITH_GFX_AV1)
1114 const BOOL av1 = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxCodecAV1);
1115 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxCodecAV1, av1))
1116 return FALSE;
1117 const UINT32 av1Profile =
1118 freerdp_settings_get_uint32(srvSettings, FreeRDP_GfxCodecAV1Profile);
1119 if (!freerdp_settings_set_uint32(clientSettings, FreeRDP_GfxCodecAV1Profile,
1120 av1Profile))
1121 return FALSE;
1122#endif
1123#if defined(WITH_GFX_AV2)
1124 const BOOL av2 = freerdp_settings_get_bool(srvSettings, FreeRDP_GfxCodecAV2);
1125 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxCodecAV2, av2))
1126 return FALSE;
1127 const UINT32 av2Profile =
1128 freerdp_settings_get_uint32(srvSettings, FreeRDP_GfxCodecAV2Profile);
1129 if (!freerdp_settings_set_uint32(clientSettings, FreeRDP_GfxCodecAV2Profile,
1130 av2Profile))
1131 return FALSE;
1132#endif
1133
1134 if (!h264 || (!avc444v2 && !avc444 && !avc420))
1135 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED;
1136
1137#if defined(WITH_GFX_AV1)
1138 if (currentCaps->version == RDPGFX_CAPVERSION_FRDP_1)
1139 {
1140 if (!av1)
1141 return FALSE;
1142
1143 pdu.capsSet->flags &=
1144 ~(RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED | RDPGFX_CAPS_FLAG_AV1_I444_DISABLED);
1145
1146 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) != 0)
1147 {
1148 if (av1Profile == 0)
1149 return FALSE;
1150 }
1151
1152 if ((av1Profile == 0) ||
1153 ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) == 0))
1154 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1155 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1156 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1157 }
1158#endif
1159#if defined(WITH_GFX_AV2)
1160 if (currentCaps->version == RDPGFX_CAPVERSION_FRDP_2)
1161 {
1162 if (!av2)
1163 return FALSE;
1164
1165 pdu.capsSet->flags &=
1166 ~(RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED | RDPGFX_CAPS_FLAG_AV1_I444_DISABLED);
1167
1168 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) != 0)
1169 {
1170 if (av2Profile == 0)
1171 return FALSE;
1172 }
1173
1174 if ((av2Profile == 0) ||
1175 ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_SUPPORTED) == 0))
1176 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1177 if ((currentCaps->flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1178 pdu.capsSet->flags |= RDPGFX_CAPS_FLAG_AV1_I444_DISABLED;
1179 }
1180#endif
1181 *rc = shadow_client_send_caps_confirm(context, client, &pdu);
1182 return TRUE;
1183 }
1184 }
1185
1186 return FALSE;
1187}
1188
1194WINPR_ATTR_NODISCARD
1195static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context,
1196 const RDPGFX_CAPS_ADVERTISE_PDU* capsAdvertise)
1197{
1198 UINT rc = ERROR_INTERNAL_ERROR;
1199
1200 UINT32 flags = 0;
1201
1202 WINPR_ASSERT(context);
1203 WINPR_ASSERT(capsAdvertise);
1204
1205 rdpShadowClient* client = (rdpShadowClient*)context->custom;
1206 WINPR_ASSERT(client);
1207 WINPR_ASSERT(context->rdpcontext);
1208
1209 const rdpSettings* srvSettings = context->rdpcontext->settings;
1210 WINPR_ASSERT(srvSettings);
1211
1212 rdpSettings* clientSettings = client->context.settings;
1213 WINPR_ASSERT(clientSettings);
1214
1215 /* Request full screen update for new gfx channel */
1216 if (!shadow_client_refresh_rect(&client->context, 0, nullptr))
1217 return rc;
1218
1219 const UINT32 capsVersions[] = {
1220#if defined(WITH_GFX_AV2)
1221 RDPGFX_CAPVERSION_FRDP_2,
1222#endif
1223#if defined(WITH_GFX_AV1)
1224 RDPGFX_CAPVERSION_FRDP_1,
1225#endif
1226#if defined(WITH_GFX_AZURE)
1227 RDPGFX_CAPVERSION_115, RDPGFX_CAPVERSION_113, RDPGFX_CAPVERSION_112,
1228 RDPGFX_CAPVERSION_111,
1229#endif
1230 RDPGFX_CAPVERSION_107, RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR,
1231 RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_103,
1232 RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_10,
1233 };
1234
1235 const BOOL h264 =
1236 shadow_encoder_prepare(client->encoder, FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444) >= 0;
1237
1238#if defined(WITH_GFX_AV1)
1239 if (freerdp_settings_get_bool(clientSettings, FreeRDP_GfxCodecAV1))
1240 {
1241 UINT32 codec = 0;
1242 const UINT32 profile =
1243 freerdp_settings_get_uint32(clientSettings, FreeRDP_GfxCodecAV1Profile);
1244 switch (profile)
1245 {
1246 case 0:
1247 codec = FREERDP_CODEC_AV1_I420;
1248 break;
1249 case 1:
1250 codec = FREERDP_CODEC_AV1_I444;
1251 break;
1252 default:
1253 return ERROR_BAD_PROFILE;
1254 }
1255 const BOOL av1 = shadow_encoder_prepare(client->encoder, codec) >= 0;
1256 if (!av1)
1257 {
1258 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxCodecAV1, FALSE))
1259 return ERROR_INTERNAL_ERROR;
1260 }
1261 }
1262#endif
1263#if defined(WITH_GFX_AV2)
1264 if (freerdp_settings_get_bool(clientSettings, FreeRDP_GfxCodecAV2))
1265 {
1266 UINT32 codec = 0;
1267 const UINT32 profile =
1268 freerdp_settings_get_uint32(clientSettings, FreeRDP_GfxCodecAV2Profile);
1269 switch (profile)
1270 {
1271 case 0:
1272 codec = FREERDP_CODEC_AV2_I420;
1273 break;
1274 case 1:
1275 codec = FREERDP_CODEC_AV2_I444;
1276 break;
1277 default:
1278 return ERROR_BAD_PROFILE;
1279 }
1280 const BOOL av2 = shadow_encoder_prepare(client->encoder, codec) >= 0;
1281 if (!av2)
1282 {
1283 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxCodecAV2, FALSE))
1284 return ERROR_INTERNAL_ERROR;
1285 }
1286 }
1287#endif
1288
1289 for (size_t x = 0; x < ARRAYSIZE(capsVersions); x++)
1290 {
1291 const UINT32 cur = capsVersions[x];
1292 if (shadow_client_caps_test_version(context, client, h264, capsAdvertise->capsSets,
1293 capsAdvertise->capsSetCount, cur, &rc))
1294 return rc;
1295 }
1296
1297 if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_81))
1298 {
1299 for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1300 {
1301 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1302
1303 if (currentCaps->version == RDPGFX_CAPVERSION_81)
1304 {
1305 RDPGFX_CAPSET caps = *currentCaps;
1307 pdu.capsSet = &caps;
1308
1309 flags = pdu.capsSet->flags;
1310
1311 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE))
1312 return rc;
1313 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE))
1314 return rc;
1315
1316 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxThinClient,
1317 (flags & RDPGFX_CAPS_FLAG_THINCLIENT) != 0))
1318 return rc;
1319 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache,
1320 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1321 return rc;
1322
1323#ifndef WITH_GFX_H264
1324 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
1325 return rc;
1326 if (h264)
1327 pdu.capsSet->flags &= ~RDPGFX_CAPS_FLAG_AVC420_ENABLED;
1328#else
1329
1330#endif
1331
1332 return shadow_client_send_caps_confirm(context, client, &pdu);
1333 }
1334 }
1335 }
1336
1337 if (!shadow_are_caps_filtered(srvSettings, RDPGFX_CAPVERSION_8))
1338 {
1339 for (UINT32 index = 0; index < capsAdvertise->capsSetCount; index++)
1340 {
1341 const RDPGFX_CAPSET* currentCaps = &capsAdvertise->capsSets[index];
1342
1343 if (currentCaps->version == RDPGFX_CAPVERSION_8)
1344 {
1345 RDPGFX_CAPSET caps = *currentCaps;
1347 pdu.capsSet = &caps;
1348 flags = pdu.capsSet->flags;
1349
1350 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444v2, FALSE))
1351 return rc;
1352 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxAVC444, FALSE))
1353 return rc;
1354 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxH264, FALSE))
1355 return rc;
1356
1357 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxThinClient,
1358 (flags & RDPGFX_CAPS_FLAG_THINCLIENT) != 0))
1359 return rc;
1360 if (!freerdp_settings_set_bool(clientSettings, FreeRDP_GfxSmallCache,
1361 (flags & RDPGFX_CAPS_FLAG_SMALL_CACHE) != 0))
1362 return rc;
1363
1364 return shadow_client_send_caps_confirm(context, client, &pdu);
1365 }
1366 }
1367 }
1368
1369 return CHANNEL_RC_UNSUPPORTED_VERSION;
1370}
1371
1372WINPR_ATTR_NODISCARD
1373static inline UINT32 rdpgfx_estimate_h264_avc420(RDPGFX_AVC420_BITMAP_STREAM* havc420)
1374{
1375 /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
1376 WINPR_ASSERT(havc420);
1377 return sizeof(UINT32) /* numRegionRects */
1378 + 10ULL /* regionRects + quantQualityVals */
1379 * havc420->meta.numRegionRects +
1380 havc420->length;
1381}
1382
1383#if defined(WITH_GFX_AV1)
1384WINPR_ATTR_NODISCARD
1385static BOOL shadow_client_av1_enabled(const rdpShadowClient* client)
1386{
1387 WINPR_ASSERT(client);
1388 return freerdp_settings_get_bool(client->context.settings, FreeRDP_GfxCodecAV1) &&
1389 (client->confirmedCaps.version == RDPGFX_CAPVERSION_FRDP_1);
1390}
1391
1392WINPR_ATTR_NODISCARD
1393static BOOL shadow_client_send_av1(rdpShadowClient* client, const BYTE* pSrcData, UINT32 nSrcStep,
1394 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1395 const RECTANGLE_16* damage, RDPGFX_SURFACE_COMMAND* cmd,
1396 const RDPGFX_START_FRAME_PDU* cmdstart,
1397 const RDPGFX_END_FRAME_PDU* cmdend)
1398{
1399 WINPR_ASSERT(client);
1400
1401 rdpShadowEncoder* encoder = client->encoder;
1402 WINPR_ASSERT(encoder);
1403
1404 UINT error = CHANNEL_RC_OK;
1405 INT32 rc = 0;
1406 RDPGFX_AVC420_BITMAP_STREAM avc420 = WINPR_C_ARRAY_INIT;
1407
1408 UINT32 flags = FREERDP_CODEC_AV1_I444;
1409 if ((client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1410 flags = FREERDP_CODEC_AV1_I420;
1411
1412 if (shadow_encoder_prepare(encoder, flags) < 0)
1413 {
1414 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AV1");
1415 return FALSE;
1416 }
1417
1418 /* The whole surface is encoded, but only the damaged part needs converting to YUV. */
1419 WINPR_ASSERT(damage);
1420 rc = freerdp_av1_compress(encoder->av1, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, damage,
1421 &avc420.data, &avc420.length, &avc420.meta);
1422 if (rc < 0)
1423 {
1424 WLog_ERR(TAG, "freerdp_av1_compress failed");
1425 return FALSE;
1426 }
1427
1428 /* rc > 0 means new data */
1429 if (rc > 0)
1430 {
1431 cmd->codecId = RDPGFX_CODECID_AV1;
1432 cmd->extra = (void*)&avc420;
1433
1434 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1435 cmdend);
1436 cmd->extra = nullptr;
1437 }
1438 free_h264_metablock(&avc420.meta);
1439
1440 if (error)
1441 {
1442 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1443 return FALSE;
1444 }
1445 return TRUE;
1446}
1447#endif
1448
1449#if defined(WITH_GFX_AV2)
1450WINPR_ATTR_NODISCARD
1451static BOOL shadow_client_send_av2(rdpShadowClient* client, const BYTE* pSrcData, UINT32 nSrcStep,
1452 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1454 const RDPGFX_START_FRAME_PDU* cmdstart,
1455 const RDPGFX_END_FRAME_PDU* cmdend)
1456{
1457 WINPR_ASSERT(client);
1458
1459 rdpShadowEncoder* encoder = client->encoder;
1460 WINPR_ASSERT(encoder);
1461
1462 UINT error = CHANNEL_RC_OK;
1463 INT32 rc = 0;
1464 RDPGFX_AVC420_BITMAP_STREAM avc420 = WINPR_C_ARRAY_INIT;
1465 RECTANGLE_16 regionRect = WINPR_C_ARRAY_INIT;
1466
1467 UINT32 flags = FREERDP_CODEC_AV2_I444;
1468 if ((client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AV1_I444_DISABLED) != 0)
1469 flags = FREERDP_CODEC_AV2_I420;
1470
1471 if (shadow_encoder_prepare(encoder, flags) < 0)
1472 {
1473 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AV2");
1474 return FALSE;
1475 }
1476
1477 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1478 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1479 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1480 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1481 regionRect.left = (UINT16)cmd->left;
1482 regionRect.top = (UINT16)cmd->top;
1483 regionRect.right = (UINT16)cmd->right;
1484 regionRect.bottom = (UINT16)cmd->bottom;
1485 rc = freerdp_av2_compress(encoder->av2, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight,
1486 &regionRect, &avc420.data, &avc420.length, &avc420.meta);
1487 if (rc < 0)
1488 {
1489 WLog_ERR(TAG, "freerdp_av2_compress failed");
1490 return FALSE;
1491 }
1492
1493 /* rc > 0 means new data */
1494 if (rc > 0)
1495 {
1496 /* AV2 uses the AV1 codec ID, the RDPGFX_CAPVERSION_FRDP_2 caps tell them apart */
1497 cmd->codecId = RDPGFX_CODECID_AV1;
1498 cmd->extra = (void*)&avc420;
1499
1500 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1501 cmdend);
1502 cmd->extra = nullptr;
1503 }
1504 free_h264_metablock(&avc420.meta);
1505
1506 if (error)
1507 {
1508 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1509 return FALSE;
1510 }
1511 return TRUE;
1512}
1513#endif
1514
1515WINPR_ATTR_NODISCARD
1516static BOOL shadow_client_send_avc444(rdpShadowClient* client, const BYTE* pSrcData,
1517 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1518 UINT16 nHeight, RDPGFX_SURFACE_COMMAND* cmd,
1519 const RDPGFX_START_FRAME_PDU* cmdstart,
1520 const RDPGFX_END_FRAME_PDU* cmdend)
1521{
1522 WINPR_ASSERT(client);
1523
1524 rdpShadowEncoder* encoder = client->encoder;
1525 WINPR_ASSERT(encoder);
1526
1527 UINT error = CHANNEL_RC_OK;
1528 INT32 rc = 0;
1529 RDPGFX_AVC444_BITMAP_STREAM avc444 = WINPR_C_ARRAY_INIT;
1530 RECTANGLE_16 regionRect = WINPR_C_ARRAY_INIT;
1531 const BOOL GfxAVC444v2 = (cmd->codecId == RDPGFX_CODECID_AVC444v2);
1532 BYTE version = GfxAVC444v2 ? 2 : 1;
1533
1534 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC444) < 0)
1535 {
1536 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC444");
1537 return FALSE;
1538 }
1539
1540 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1541 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1542 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1543 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1544 regionRect.left = (UINT16)cmd->left;
1545 regionRect.top = (UINT16)cmd->top;
1546 regionRect.right = (UINT16)cmd->right;
1547 regionRect.bottom = (UINT16)cmd->bottom;
1548 rc = avc444_compress(encoder->h264, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, version,
1549 &regionRect, &avc444.LC, &avc444.bitstream[0].data,
1550 &avc444.bitstream[0].length, &avc444.bitstream[1].data,
1551 &avc444.bitstream[1].length, &avc444.bitstream[0].meta,
1552 &avc444.bitstream[1].meta);
1553 if (rc < 0)
1554 {
1555 WLog_ERR(TAG, "avc420_compress failed for avc444");
1556 return FALSE;
1557 }
1558
1559 /* rc > 0 means new data */
1560 if (rc > 0)
1561 {
1562 avc444.cbAvc420EncodedBitstream1 = rdpgfx_estimate_h264_avc420(&avc444.bitstream[0]);
1563 cmd->extra = (void*)&avc444;
1564 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1565 cmdend);
1566 cmd->extra = nullptr;
1567 }
1568
1569 free_h264_metablock(&avc444.bitstream[0].meta);
1570 free_h264_metablock(&avc444.bitstream[1].meta);
1571 if (error)
1572 {
1573 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1574 return FALSE;
1575 }
1576 return TRUE;
1577}
1578
1579WINPR_ATTR_NODISCARD
1580static BOOL shadow_client_send_avc420(rdpShadowClient* client, const BYTE* pSrcData,
1581 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1582 UINT16 nHeight, RDPGFX_SURFACE_COMMAND* cmd,
1583 const RDPGFX_START_FRAME_PDU* cmdstart,
1584 const RDPGFX_END_FRAME_PDU* cmdend)
1585{
1586 WINPR_ASSERT(client);
1587
1588 rdpShadowEncoder* encoder = client->encoder;
1589 WINPR_ASSERT(encoder);
1590
1591 UINT error = CHANNEL_RC_OK;
1592 INT32 rc = 0;
1593 RDPGFX_AVC420_BITMAP_STREAM avc420 = WINPR_C_ARRAY_INIT;
1594 RECTANGLE_16 regionRect;
1595
1596 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_AVC420) < 0)
1597 {
1598 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_AVC420");
1599 return FALSE;
1600 }
1601
1602 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1603 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1604 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1605 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1606 regionRect.left = (UINT16)cmd->left;
1607 regionRect.top = (UINT16)cmd->top;
1608 regionRect.right = (UINT16)cmd->right;
1609 regionRect.bottom = (UINT16)cmd->bottom;
1610 rc = avc420_compress(encoder->h264, pSrcData, SrcFormat, nSrcStep, nWidth, nHeight, &regionRect,
1611 &avc420.data, &avc420.length, &avc420.meta);
1612 if (rc < 0)
1613 {
1614 WLog_ERR(TAG, "avc420_compress failed");
1615 return FALSE;
1616 }
1617
1618 /* rc > 0 means new data */
1619 if (rc > 0)
1620 {
1621 cmd->codecId = RDPGFX_CODECID_AVC420;
1622 cmd->extra = (void*)&avc420;
1623 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1624 cmdend);
1625 cmd->extra = nullptr;
1626 }
1627 free_h264_metablock(&avc420.meta);
1628
1629 if (error)
1630 {
1631 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1632 return FALSE;
1633 }
1634 return TRUE;
1635}
1636
1637WINPR_ATTR_NODISCARD
1638static BOOL shadow_client_send_rfx(rdpShadowClient* client, const BYTE* pSrcData, UINT32 nSrcStep,
1639 UINT32 SrcFormat, UINT16 nWidth, UINT16 nHeight,
1641 const RDPGFX_START_FRAME_PDU* cmdstart,
1642 const RDPGFX_END_FRAME_PDU* cmdend)
1643{
1644 WINPR_ASSERT(client);
1645
1646 rdpShadowEncoder* encoder = client->encoder;
1647 WINPR_ASSERT(encoder);
1648
1649 UINT error = CHANNEL_RC_OK;
1650 BOOL rc = 0;
1651
1652 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
1653 {
1654 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
1655 return FALSE;
1656 }
1657
1658 const UINT32 rfxFormat = rfx_context_get_pixel_format(encoder->rfx);
1659 if (rfxFormat != SrcFormat)
1660 {
1661 WLog_ERR(TAG, "RFX context pixel format mismatch %s, expected %s",
1662 FreeRDPGetColorFormatName(rfxFormat), FreeRDPGetColorFormatName(SrcFormat));
1663 return FALSE;
1664 }
1665
1666 wStream* s = Stream_New(nullptr, 1024);
1667 WINPR_ASSERT(s);
1668
1669 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1670 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1671 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1672 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1673
1674 /* GFX RFX dirty tile skipping: split the dirty rect onto the 64x64
1675 * surface tile grid and compare each tile against the encoder snapshot
1676 * of the last encoded content (shadow_rfx_dirty.c). Only tiles whose
1677 * content changed are passed to the RFX encoder. A missing or
1678 * mismatching snapshot (first frame, ResetGraphics, resize, new client)
1679 * treats every tile as changed and degrades to full encoding. */
1680 {
1681 UINT16 numRects = 0;
1682 RFX_RECT* rects = nullptr;
1683
1684 if (shadow_rfx_plan_tiles(encoder, pSrcData, nSrcStep, cmd, nWidth, nHeight, &rects,
1685 &numRects) < 0)
1686 {
1687 WLog_ERR(TAG, "shadow_rfx_plan_tiles failed");
1688 Stream_Free(s, TRUE);
1689 free(rects);
1690 return FALSE;
1691 }
1692
1693 if (numRects == 0)
1694 {
1695 /* Every tile of this frame is byte-identical to the last encoded
1696 * content: skip the whole frame (no surface command: StartFrame/
1697 * EndFrame are sent paired with SurfaceFrameCommand, so no
1698 * dangling frame semantics). Give the frame id back to the
1699 * encoder: skipped frames are never acknowledged by the client,
1700 * not returning it would permanently inflate the in-flight depth
1701 * and stall the preferred_fps backpressure. */
1702 encoder->frameId--;
1703 Stream_Free(s, TRUE);
1704 free(rects);
1705 return TRUE;
1706 }
1707
1708 rc = rfx_compose_message(encoder->rfx, s, rects, numRects, pSrcData, nWidth, nHeight,
1709 nSrcStep);
1710
1711 if (rc)
1712 {
1713 const size_t pos = Stream_GetPosition(s);
1714 shadow_rfx_commit_tiles(encoder, pSrcData, nSrcStep, rects, numRects,
1715 WINPR_ASSERTING_INT_CAST(UINT32, pos));
1716 }
1717
1718 free(rects);
1719 }
1720
1721 if (!rc)
1722 {
1723 WLog_ERR(TAG, "rfx_compose_message failed");
1724 Stream_Free(s, TRUE);
1725 return FALSE;
1726 }
1727
1728 /* rc > 0 means new data */
1729 if (rc > 0)
1730 {
1731 const size_t pos = Stream_GetPosition(s);
1732 WINPR_ASSERT(pos <= UINT32_MAX);
1733
1734 cmd->codecId = RDPGFX_CODECID_CAVIDEO;
1735 cmd->data = Stream_Buffer(s);
1736 cmd->length = (UINT32)pos;
1737
1738 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1739 cmdend);
1740 cmd->data = nullptr;
1741 }
1742
1743 Stream_Free(s, TRUE);
1744 if (error)
1745 {
1746 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1747 return FALSE;
1748 }
1749 return TRUE;
1750}
1751
1752WINPR_ATTR_NODISCARD
1753static BOOL shadow_client_send_progressive(rdpShadowClient* client, const BYTE* pSrcData,
1754 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nWidth,
1755 UINT16 nHeight, RDPGFX_SURFACE_COMMAND* cmd,
1756 const RDPGFX_START_FRAME_PDU* cmdstart,
1757 const RDPGFX_END_FRAME_PDU* cmdend)
1758{
1759 WINPR_ASSERT(client);
1760
1761 rdpShadowEncoder* encoder = client->encoder;
1762 WINPR_ASSERT(encoder);
1763
1764 UINT error = CHANNEL_RC_OK;
1765 INT32 rc = 0;
1766 REGION16 region;
1767 RECTANGLE_16 regionRect;
1768
1769 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PROGRESSIVE) < 0)
1770 {
1771 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PROGRESSIVE");
1772 return FALSE;
1773 }
1774
1775 WINPR_ASSERT(cmd->left <= UINT16_MAX);
1776 WINPR_ASSERT(cmd->top <= UINT16_MAX);
1777 WINPR_ASSERT(cmd->right <= UINT16_MAX);
1778 WINPR_ASSERT(cmd->bottom <= UINT16_MAX);
1779 regionRect.left = (UINT16)cmd->left;
1780 regionRect.top = (UINT16)cmd->top;
1781 regionRect.right = (UINT16)cmd->right;
1782 regionRect.bottom = (UINT16)cmd->bottom;
1783 region16_init(&region);
1784 if (!region16_union_rect(&region, &region, &regionRect))
1785 {
1786 region16_uninit(&region);
1787 return FALSE;
1788 }
1789 rc = progressive_compress(encoder->progressive, pSrcData, nSrcStep * nHeight, SrcFormat, nWidth,
1790 nHeight, nSrcStep, &region, &cmd->data, &cmd->length);
1791 region16_uninit(&region);
1792 if (rc < 0)
1793 {
1794 WLog_ERR(TAG, "progressive_compress failed");
1795 return FALSE;
1796 }
1797
1798 /* rc > 0 means new data */
1799 if (rc > 0)
1800 {
1801 cmd->codecId = RDPGFX_CODECID_CAPROGRESSIVE;
1802
1803 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart,
1804 cmdend);
1805 }
1806 cmd->data = nullptr;
1807
1808 if (error)
1809 {
1810 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1811 return FALSE;
1812 }
1813 return TRUE;
1814}
1815
1816WINPR_ATTR_NODISCARD
1817static BOOL shadow_client_send_planar(rdpShadowClient* client, const BYTE* pSrcData,
1818 UINT32 nSrcStep, UINT32 SrcFormat,
1820 const RDPGFX_START_FRAME_PDU* cmdstart,
1821 const RDPGFX_END_FRAME_PDU* cmdend)
1822{
1823 WINPR_ASSERT(client);
1824
1825 rdpShadowEncoder* encoder = client->encoder;
1826 WINPR_ASSERT(encoder);
1827
1828 UINT error = CHANNEL_RC_OK;
1829 const UINT32 w = cmd->right - cmd->left;
1830 const UINT32 h = cmd->bottom - cmd->top;
1831 const BYTE* src =
1832 &pSrcData[cmd->top * nSrcStep + cmd->left * FreeRDPGetBytesPerPixel(SrcFormat)];
1833 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
1834 {
1835 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PLANAR");
1836 return FALSE;
1837 }
1838
1839 const BOOL rc = freerdp_bitmap_planar_context_reset(encoder->planar, w, h);
1840 if (!rc)
1841 return FALSE;
1842
1843 freerdp_planar_topdown_image(encoder->planar, TRUE);
1844
1845 cmd->data = freerdp_bitmap_compress_planar(encoder->planar, src, SrcFormat, w, h, nSrcStep,
1846 nullptr, &cmd->length);
1847 WINPR_ASSERT(cmd->data || (cmd->length == 0));
1848
1849 cmd->codecId = RDPGFX_CODECID_PLANAR;
1850
1851 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart, cmdend);
1852 free(cmd->data);
1853 cmd->data = nullptr;
1854
1855 if (error)
1856 {
1857 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1858 return FALSE;
1859 }
1860 return TRUE;
1861}
1862
1863WINPR_ATTR_NODISCARD
1864static BOOL shadow_client_send_uncompressed(rdpShadowClient* client, const BYTE* pSrcData,
1865 UINT32 nSrcStep, UINT32 SrcFormat,
1867 const RDPGFX_START_FRAME_PDU* cmdstart,
1868 const RDPGFX_END_FRAME_PDU* cmdend)
1869{
1870 WINPR_ASSERT(client);
1871 WINPR_ASSERT(cmd);
1872 WINPR_ASSERT(pSrcData);
1873 WINPR_ASSERT(cmdstart);
1874 WINPR_ASSERT(cmdend);
1875
1876 UINT error = CHANNEL_RC_OK;
1877
1878 WINPR_ASSERT(cmd->right >= cmd->left);
1879 WINPR_ASSERT(cmd->bottom >= cmd->top);
1880
1881 const UINT32 w = cmd->right - cmd->left;
1882 const UINT32 h = cmd->bottom - cmd->top;
1883 if ((w == 0) || (h == 0) || (w > UINT32_MAX / 4 / h))
1884 {
1885 WLog_ERR(TAG, "input width=%" PRIu32 " x height=%" PRIu32 " is 0 or exceeds UINT32_MAX", w,
1886 h);
1887 return FALSE;
1888 }
1889 const UINT32 length = w * 4ul * h;
1890
1891 if (length == 0)
1892 {
1893 WLog_ERR(TAG, "input length == 0");
1894 return FALSE;
1895 }
1896
1897 BYTE* data = malloc(length);
1898 if (!data)
1899 return FALSE;
1900
1901 BOOL rc = freerdp_image_copy_no_overlap(data, cmd->format, 0, 0, 0, w, h, pSrcData, SrcFormat,
1902 nSrcStep, cmd->left, cmd->top, nullptr, 0);
1903 if (!rc)
1904 {
1905 free(data);
1906 return FALSE;
1907 }
1908
1909 cmd->data = data;
1910 cmd->length = length;
1911 cmd->codecId = RDPGFX_CODECID_UNCOMPRESSED;
1912
1913 IFCALLRET(client->rdpgfx->SurfaceFrameCommand, error, client->rdpgfx, cmd, cmdstart, cmdend);
1914 free(data);
1915 cmd->data = nullptr;
1916 if (error)
1917 {
1918 WLog_ERR(TAG, "SurfaceFrameCommand failed with error %" PRIu32 "", error);
1919 return FALSE;
1920 }
1921 return TRUE;
1922}
1923
1924WINPR_ATTR_NODISCARD
1925static BOOL shadow_avc444_enabled(const rdpShadowClient* client)
1926{
1927 WINPR_ASSERT(client);
1928 switch (client->confirmedCaps.version)
1929 {
1930 case RDPGFX_CAPVERSION_10:
1931 case RDPGFX_CAPVERSION_101:
1932 case RDPGFX_CAPVERSION_102:
1933 case RDPGFX_CAPVERSION_103:
1934 case RDPGFX_CAPVERSION_104:
1935 case RDPGFX_CAPVERSION_105:
1936 case RDPGFX_CAPVERSION_106:
1937 case RDPGFX_CAPVERSION_107:
1938#if defined(WITH_GFX_AZURE)
1939 case RDPGFX_CAPVERSION_111:
1940 case RDPGFX_CAPVERSION_112:
1941 case RDPGFX_CAPVERSION_113:
1942 case RDPGFX_CAPVERSION_115:
1943#endif
1944 return (client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AVC_DISABLED) == 0;
1945
1946 default:
1947 return FALSE;
1948 }
1949}
1950
1951WINPR_ATTR_NODISCARD
1952static BOOL shadow_avc420_enabled(const rdpShadowClient* client)
1953{
1954 if (shadow_avc444_enabled(client))
1955 return TRUE;
1956 if (client->confirmedCaps.version != RDPGFX_CAPVERSION_81)
1957 return FALSE;
1958 return (client->confirmedCaps.flags & RDPGFX_CAPS_FLAG_AVC420_ENABLED) != 0;
1959}
1960
1966WINPR_ATTR_NODISCARD
1967static BOOL shadow_client_send_surface_gfx(rdpShadowClient* client, const BYTE* pSrcData,
1968 UINT32 nSrcStep, UINT32 SrcFormat, UINT16 nXSrc,
1969 UINT16 nYSrc, UINT16 nWidth, UINT16 nHeight,
1970 UINT16 srcWidth, UINT16 srcHeight,
1971 const RECTANGLE_16* damage)
1972{
1973 const rdpContext* context = (const rdpContext*)client;
1974 RDPGFX_SURFACE_COMMAND cmd = WINPR_C_ARRAY_INIT;
1975 RDPGFX_START_FRAME_PDU cmdstart = WINPR_C_ARRAY_INIT;
1976 RDPGFX_END_FRAME_PDU cmdend = WINPR_C_ARRAY_INIT;
1977 SYSTEMTIME sTime = WINPR_C_ARRAY_INIT;
1978
1979 if (!context || !pSrcData || !damage)
1980 return FALSE;
1981
1982 const rdpSettings* settings = context->settings;
1983 rdpShadowEncoder* encoder = client->encoder;
1984
1985 if (!settings || !encoder)
1986 return FALSE;
1987
1988 if (client->first_frame)
1989 {
1990 if (encoder->rfx)
1991 {
1992 if (!rfx_context_reset(encoder->rfx, nWidth, nHeight))
1993 return FALSE;
1994 }
1995 /* After ResetGraphics the client surface has no dependable state:
1996 * invalidate the RFX dirty skip snapshot so the next frame is
1997 * encoded in full. */
1998 shadow_rfx_invalidate_snapshot(encoder);
1999 client->first_frame = FALSE;
2000 }
2001
2002 cmdstart.frameId = shadow_encoder_create_frame_id(encoder);
2003 GetSystemTime(&sTime);
2004 cmdstart.timestamp = (UINT32)(sTime.wHour << 22U | sTime.wMinute << 16U | sTime.wSecond << 10U |
2005 sTime.wMilliseconds);
2006 cmdend.frameId = cmdstart.frameId;
2007 cmd.surfaceId = client->surfaceId;
2008 cmd.format = PIXEL_FORMAT_BGRX32;
2009 cmd.left = nXSrc;
2010 cmd.top = nYSrc;
2011 cmd.right = cmd.left + nWidth;
2012 cmd.bottom = cmd.top + nHeight;
2013 cmd.width = nWidth;
2014 cmd.height = nHeight;
2015
2016#if defined(WITH_GFX_AV2)
2017 if (freerdp_settings_get_bool(settings, FreeRDP_GfxCodecAV2))
2018 {
2019 if (client->confirmedCaps.version == RDPGFX_CAPVERSION_FRDP_2)
2020 {
2021 return shadow_client_send_av2(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
2022 &cmd, &cmdstart, &cmdend);
2023 }
2024 }
2025#endif
2026
2027#if defined(WITH_GFX_AV1)
2028 if (shadow_client_av1_enabled(client))
2029 {
2030 return shadow_client_send_av1(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
2031 damage, &cmd, &cmdstart, &cmdend);
2032 }
2033#endif
2034
2035 const UINT32 id = freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
2036#ifdef WITH_GFX_H264
2037 const BOOL GfxH264 = freerdp_settings_get_bool(settings, FreeRDP_GfxH264);
2038 const BOOL GfxAVC444 = freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444);
2039 const BOOL GfxAVC444v2 = freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444v2);
2040 if (GfxAVC444 || GfxAVC444v2)
2041 {
2042 if (shadow_avc444_enabled(client))
2043 {
2044 cmd.codecId = GfxAVC444v2 ? RDPGFX_CODECID_AVC444v2 : RDPGFX_CODECID_AVC444;
2045 return shadow_client_send_avc444(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
2046 &cmd, &cmdstart, &cmdend);
2047 }
2048 }
2049
2050 if (GfxH264 && shadow_avc420_enabled(client))
2051 {
2052 return shadow_client_send_avc420(client, pSrcData, nSrcStep, SrcFormat, nWidth, nHeight,
2053 &cmd, &cmdstart, &cmdend);
2054 }
2055
2056#endif
2057 if (freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) && (id != 0))
2058 {
2059 /* The RFX source image dims must be the whole surface: the tile grid
2060 * is aligned to absolute surface coordinates and edge tiles are
2061 * truncated at the surface bounds. */
2062 return shadow_client_send_rfx(client, pSrcData, nSrcStep, SrcFormat, srcWidth, srcHeight,
2063 &cmd, &cmdstart, &cmdend);
2064 }
2065
2066 if (freerdp_settings_get_bool(settings, FreeRDP_GfxProgressive))
2067 {
2068 return shadow_client_send_progressive(client, pSrcData, nSrcStep, SrcFormat, nWidth,
2069 nHeight, &cmd, &cmdstart, &cmdend);
2070 }
2071
2072 if (freerdp_settings_get_bool(settings, FreeRDP_GfxPlanar))
2073 {
2074 return shadow_client_send_planar(client, pSrcData, nSrcStep, SrcFormat, &cmd, &cmdstart,
2075 &cmdend);
2076 }
2077
2078 return shadow_client_send_uncompressed(client, pSrcData, nSrcStep, SrcFormat, &cmd, &cmdstart,
2079 &cmdend);
2080}
2081
2082WINPR_ATTR_NODISCARD
2083static BOOL stream_surface_bits_supported(const rdpSettings* settings)
2084{
2085 const UINT32 supported =
2086 freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
2087 return ((supported & SURFCMDS_STREAM_SURFACE_BITS) != 0);
2088}
2089
2090WINPR_ATTR_NODISCARD
2091static BOOL set_surface_bits_supported(const rdpSettings* settings)
2092{
2093 const UINT32 supported =
2094 freerdp_settings_get_uint32(settings, FreeRDP_SurfaceCommandsSupported);
2095 return ((supported & SURFCMDS_SET_SURFACE_BITS) != 0);
2096}
2097
2098WINPR_ATTR_NODISCARD
2099static BOOL is_surface_command_supported(const rdpSettings* settings)
2100{
2101 if (stream_surface_bits_supported(settings))
2102 {
2103 const UINT32 rfxID = freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
2104 const BOOL supported = freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec);
2105 if (supported && (rfxID != 0))
2106 return TRUE;
2107 }
2108 if (set_surface_bits_supported(settings))
2109 {
2110 const UINT32 nsID = freerdp_settings_get_uint32(settings, FreeRDP_NSCodecId);
2111 const BOOL supported = freerdp_settings_get_bool(settings, FreeRDP_NSCodec);
2112 if (supported && (nsID != 0))
2113 return TRUE;
2114 }
2115 return FALSE;
2116}
2117
2123WINPR_ATTR_NODISCARD
2124static BOOL shadow_client_send_surface_bits(rdpShadowClient* client, BYTE* pSrcData,
2125 UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
2126 UINT16 nWidth, UINT16 nHeight)
2127{
2128 BOOL ret = TRUE;
2129 BOOL first = 0;
2130 BOOL last = 0;
2131 wStream* s = nullptr;
2132 size_t numMessages = 0;
2133 UINT32 frameId = 0;
2134 rdpUpdate* update = nullptr;
2135 rdpContext* context = (rdpContext*)client;
2136 rdpSettings* settings = nullptr;
2137 rdpShadowEncoder* encoder = nullptr;
2138 SURFACE_BITS_COMMAND cmd = WINPR_C_ARRAY_INIT;
2139
2140 if (!context || !pSrcData)
2141 return FALSE;
2142
2143 update = context->update;
2144 settings = context->settings;
2145 encoder = client->encoder;
2146
2147 if (!update || !settings || !encoder)
2148 return FALSE;
2149
2150 if (encoder->frameAck)
2151 frameId = shadow_encoder_create_frame_id(encoder);
2152
2153 // TODO: Check FreeRDP_RemoteFxCodecMode if we should send RFX IMAGE or VIDEO data
2154 const UINT32 nsID = freerdp_settings_get_uint32(settings, FreeRDP_NSCodecId);
2155 const UINT32 rfxID = freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId);
2156 if (stream_surface_bits_supported(settings) &&
2157 freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) && (rfxID != 0))
2158 {
2159 RFX_RECT rect = WINPR_C_ARRAY_INIT;
2160
2161 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_REMOTEFX) < 0)
2162 {
2163 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_REMOTEFX");
2164 return FALSE;
2165 }
2166
2167 s = encoder->bs;
2168 rect.x = nXSrc;
2169 rect.y = nYSrc;
2170 rect.width = nWidth;
2171 rect.height = nHeight;
2172
2173 const UINT32 MultifragMaxRequestSize =
2174 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize);
2175 RFX_MESSAGE_LIST* messages =
2176 rfx_encode_messages(encoder->rfx, &rect, 1, pSrcData,
2177 freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth),
2178 freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight),
2179 nSrcStep, &numMessages, MultifragMaxRequestSize);
2180 if (!messages)
2181 {
2182 WLog_ERR(TAG, "rfx_encode_messages failed");
2183 return FALSE;
2184 }
2185
2186 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
2187 WINPR_ASSERT(rfxID <= UINT16_MAX);
2188 cmd.bmp.codecID = (UINT16)rfxID;
2189 cmd.destLeft = 0;
2190 cmd.destTop = 0;
2191 cmd.destRight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
2192 cmd.destBottom = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
2193 cmd.bmp.bpp = 32;
2194 cmd.bmp.flags = 0;
2195 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth) <= UINT16_MAX);
2196 WINPR_ASSERT(freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight) <= UINT16_MAX);
2197 cmd.bmp.width = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
2198 cmd.bmp.height = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
2199 cmd.skipCompression = TRUE;
2200
2201 for (size_t i = 0; i < numMessages; i++)
2202 {
2203 Stream_ResetPosition(s);
2204
2205 const RFX_MESSAGE* msg = rfx_message_list_get(messages, i);
2206 if (!rfx_write_message(encoder->rfx, s, msg))
2207 {
2208 WLog_ERR(TAG, "rfx_write_message failed");
2209 ret = FALSE;
2210 break;
2211 }
2212
2213 cmd.bmp.bitmapDataLength = WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetPosition(s));
2214 cmd.bmp.bitmapData = Stream_Buffer(s);
2215 first = (i == 0);
2216 last = ((i + 1) == numMessages);
2217
2218 if (!encoder->frameAck)
2219 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
2220 else
2221 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last,
2222 frameId);
2223
2224 if (!ret)
2225 {
2226 WLog_ERR(TAG, "Send surface bits(RemoteFxCodec) failed");
2227 break;
2228 }
2229 }
2230
2231 rfx_message_list_free(messages);
2232 }
2233 else if (set_surface_bits_supported(settings) &&
2234 freerdp_settings_get_bool(settings, FreeRDP_NSCodec) && (nsID != 0))
2235 {
2236 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_NSCODEC) < 0)
2237 {
2238 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_NSCODEC");
2239 return FALSE;
2240 }
2241
2242 s = encoder->bs;
2243 Stream_ResetPosition(s);
2244 pSrcData = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)];
2245 if (!nsc_compose_message(encoder->nsc, s, pSrcData, nWidth, nHeight, nSrcStep))
2246 return FALSE;
2247
2248 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
2249 cmd.bmp.bpp = 32;
2250 WINPR_ASSERT(nsID <= UINT16_MAX);
2251 cmd.bmp.codecID = (UINT16)nsID;
2252 cmd.destLeft = nXSrc;
2253 cmd.destTop = nYSrc;
2254 cmd.destRight = cmd.destLeft + nWidth;
2255 cmd.destBottom = cmd.destTop + nHeight;
2256 cmd.bmp.width = nWidth;
2257 cmd.bmp.height = nHeight;
2258
2259 cmd.bmp.bitmapDataLength = WINPR_ASSERTING_INT_CAST(UINT32, Stream_GetPosition(s));
2260 cmd.bmp.bitmapData = Stream_Buffer(s);
2261 first = TRUE;
2262 last = TRUE;
2263
2264 if (!encoder->frameAck)
2265 IFCALLRET(update->SurfaceBits, ret, update->context, &cmd);
2266 else
2267 IFCALLRET(update->SurfaceFrameBits, ret, update->context, &cmd, first, last, frameId);
2268
2269 if (!ret)
2270 {
2271 WLog_ERR(TAG, "Send surface bits(NSCodec) failed");
2272 }
2273 }
2274
2275 return ret;
2276}
2277
2283WINPR_ATTR_NODISCARD
2284static BOOL shadow_client_send_bitmap_update(rdpShadowClient* client, BYTE* pSrcData,
2285 UINT32 nSrcStep, UINT16 nXSrc, UINT16 nYSrc,
2286 UINT16 nWidth, UINT16 nHeight)
2287{
2288 BOOL ret = TRUE;
2289 BYTE* data = nullptr;
2290 BYTE* buffer = nullptr;
2291 UINT32 k = 0;
2292 UINT32 yIdx = 0;
2293 UINT32 xIdx = 0;
2294 UINT32 rows = 0;
2295 UINT32 cols = 0;
2296 UINT32 DstSize = 0;
2297 UINT32 SrcFormat = 0;
2298 BITMAP_DATA* bitmap = nullptr;
2299 rdpContext* context = (rdpContext*)client;
2300 UINT32 totalBitmapSize = 0;
2301 UINT32 updateSizeEstimate = 0;
2302 BITMAP_DATA* bitmapData = nullptr;
2303 BITMAP_UPDATE bitmapUpdate = WINPR_C_ARRAY_INIT;
2304
2305 if (!context || !pSrcData)
2306 return FALSE;
2307
2308 rdpUpdate* update = context->update;
2309 rdpSettings* settings = context->settings;
2310 rdpShadowEncoder* encoder = client->encoder;
2311
2312 if (!update || !settings || !encoder)
2313 return FALSE;
2314
2315 const UINT32 maxUpdateSize =
2316 freerdp_settings_get_uint32(settings, FreeRDP_MultifragMaxRequestSize);
2317 if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) < 32)
2318 {
2319 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_INTERLEAVED) < 0)
2320 {
2321 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_INTERLEAVED");
2322 return FALSE;
2323 }
2324 }
2325 else
2326 {
2327 if (shadow_encoder_prepare(encoder, FREERDP_CODEC_PLANAR) < 0)
2328 {
2329 WLog_ERR(TAG, "Failed to prepare encoder FREERDP_CODEC_PLANAR");
2330 return FALSE;
2331 }
2332 }
2333
2334 SrcFormat = PIXEL_FORMAT_BGRX32;
2335
2336 if ((nXSrc % 4) != 0)
2337 {
2338 nWidth += (nXSrc % 4);
2339 nXSrc -= (nXSrc % 4);
2340 }
2341
2342 if ((nYSrc % 4) != 0)
2343 {
2344 nHeight += (nYSrc % 4);
2345 nYSrc -= (nYSrc % 4);
2346 }
2347
2348 rows = (nHeight / 64) + ((nHeight % 64) ? 1 : 0);
2349 cols = (nWidth / 64) + ((nWidth % 64) ? 1 : 0);
2350 k = 0;
2351 totalBitmapSize = 0;
2352 bitmapUpdate.number = rows * cols;
2353
2354 if (!(bitmapData = (BITMAP_DATA*)calloc(bitmapUpdate.number, sizeof(BITMAP_DATA))))
2355 return FALSE;
2356
2357 bitmapUpdate.rectangles = bitmapData;
2358
2359 if ((nWidth % 4) != 0)
2360 {
2361 nWidth += (4 - (nWidth % 4));
2362 }
2363
2364 if ((nHeight % 4) != 0)
2365 {
2366 nHeight += (4 - (nHeight % 4));
2367 }
2368
2369 for (yIdx = 0; yIdx < rows; yIdx++)
2370 {
2371 for (xIdx = 0; xIdx < cols; xIdx++)
2372 {
2373 bitmap = &bitmapData[k];
2374 bitmap->width = 64;
2375 bitmap->height = 64;
2376 bitmap->destLeft = nXSrc + (xIdx * 64);
2377 bitmap->destTop = nYSrc + (yIdx * 64);
2378
2379 if (((INT64)bitmap->destLeft + bitmap->width) > (nXSrc + nWidth))
2380 bitmap->width = (UINT32)(nXSrc + nWidth) - bitmap->destLeft;
2381
2382 if (((INT64)bitmap->destTop + bitmap->height) > (nYSrc + nHeight))
2383 bitmap->height = (UINT32)(nYSrc + nHeight) - bitmap->destTop;
2384
2385 bitmap->destRight = bitmap->destLeft + bitmap->width - 1;
2386 bitmap->destBottom = bitmap->destTop + bitmap->height - 1;
2387 bitmap->compressed = TRUE;
2388
2389 if ((bitmap->width < 4) || (bitmap->height < 4))
2390 continue;
2391
2392 if (freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth) < 32)
2393 {
2394 UINT32 bitsPerPixel = freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
2395 UINT32 bytesPerPixel = (bitsPerPixel + 7) / 8;
2396 DstSize = 64 * 64 * 4;
2397 buffer = encoder->grid[k];
2398
2399 ret = interleaved_compress(
2400 encoder->interleaved, buffer, &DstSize, bitmap->width, bitmap->height, pSrcData,
2401 SrcFormat, nSrcStep, bitmap->destLeft, bitmap->destTop, nullptr, bitsPerPixel);
2402 if (!ret)
2403 goto out;
2404 bitmap->bitmapDataStream = buffer;
2405 bitmap->bitmapLength = DstSize;
2406 bitmap->bitsPerPixel = bitsPerPixel;
2407 bitmap->cbScanWidth = bitmap->width * bytesPerPixel;
2408 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * bytesPerPixel;
2409 }
2410 else
2411 {
2412 UINT32 dstSize = 0;
2413 buffer = encoder->grid[k];
2414 data = &pSrcData[(bitmap->destTop * nSrcStep) + (bitmap->destLeft * 4)];
2415
2416 buffer =
2417 freerdp_bitmap_compress_planar(encoder->planar, data, SrcFormat, bitmap->width,
2418 bitmap->height, nSrcStep, buffer, &dstSize);
2419 bitmap->bitmapDataStream = buffer;
2420 bitmap->bitmapLength = dstSize;
2421 bitmap->bitsPerPixel = 32;
2422 bitmap->cbScanWidth = bitmap->width * 4;
2423 bitmap->cbUncompressedSize = bitmap->width * bitmap->height * 4;
2424 }
2425
2426 bitmap->cbCompFirstRowSize = 0;
2427 bitmap->cbCompMainBodySize = bitmap->bitmapLength;
2428 totalBitmapSize += bitmap->bitmapLength;
2429 k++;
2430 }
2431 }
2432
2433 bitmapUpdate.number = k;
2434 updateSizeEstimate = totalBitmapSize + (k * bitmapUpdate.number) + 16;
2435
2436 if (updateSizeEstimate > maxUpdateSize)
2437 {
2438 UINT32 i = 0;
2439 UINT32 j = 0;
2440 UINT32 updateSize = 0;
2441 UINT32 newUpdateSize = 0;
2442 BITMAP_DATA* fragBitmapData = nullptr;
2443
2444 if (k > 0)
2445 fragBitmapData = (BITMAP_DATA*)calloc(k, sizeof(BITMAP_DATA));
2446
2447 if (!fragBitmapData)
2448 {
2449 WLog_ERR(TAG, "Failed to allocate memory for fragBitmapData");
2450 ret = FALSE;
2451 goto out;
2452 }
2453
2454 bitmapUpdate.rectangles = fragBitmapData;
2455 i = j = 0;
2456 updateSize = 1024;
2457
2458 while (i < k)
2459 {
2460 newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16);
2461
2462 if (newUpdateSize < maxUpdateSize)
2463 {
2464 CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA));
2465 updateSize = newUpdateSize;
2466 }
2467
2468 if ((newUpdateSize >= maxUpdateSize) || (i + 1) >= k)
2469 {
2470 bitmapUpdate.number = j;
2471 ret = BitmapUpdateProxy(client, &bitmapUpdate);
2472
2473 if (!ret)
2474 break;
2475
2476 updateSize = 1024;
2477 j = 0;
2478 }
2479 }
2480
2481 free(fragBitmapData);
2482 }
2483 else
2484 {
2485 ret = BitmapUpdateProxy(client, &bitmapUpdate);
2486 }
2487
2488out:
2489 free(bitmapData);
2490 return ret;
2491}
2492
2498WINPR_ATTR_NODISCARD
2499static BOOL shadow_client_send_surface_update(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2500{
2501 BOOL ret = TRUE;
2502 INT64 nXSrc = 0;
2503 INT64 nYSrc = 0;
2504 INT64 nWidth = 0;
2505 INT64 nHeight = 0;
2506 rdpContext* context = (rdpContext*)client;
2507 rdpSettings* settings = nullptr;
2508 rdpShadowServer* server = nullptr;
2509 rdpShadowSurface* surface = nullptr;
2510 REGION16 invalidRegion;
2511 RECTANGLE_16 surfaceRect;
2512 const RECTANGLE_16* extents = nullptr;
2513 BYTE* pSrcData = nullptr;
2514 UINT32 nSrcStep = 0;
2515 UINT32 SrcFormat = 0;
2516 UINT32 numRects = 0;
2517 const RECTANGLE_16* rects = nullptr;
2518
2519 if (!context || !pStatus)
2520 return FALSE;
2521
2522 settings = context->settings;
2523 server = client->server;
2524
2525 if (!settings || !server)
2526 return FALSE;
2527
2528 surface = client->inLobby ? server->lobby : server->surface;
2529
2530 if (!surface)
2531 return FALSE;
2532
2533 {
2534 EnterCriticalSection(&(client->lock));
2535 region16_init(&invalidRegion);
2536
2537 const BOOL res = region16_copy(&invalidRegion, &(client->invalidRegion));
2538 region16_clear(&(client->invalidRegion));
2539 LeaveCriticalSection(&(client->lock));
2540 if (!res)
2541 goto out;
2542 }
2543
2544 EnterCriticalSection(&surface->lock);
2545 rects = region16_rects(&(surface->invalidRegion), &numRects);
2546
2547 for (UINT32 index = 0; index < numRects; index++)
2548 {
2549 if (!region16_union_rect(&invalidRegion, &invalidRegion, &rects[index]))
2550 goto out;
2551 }
2552
2553 surfaceRect.left = 0;
2554 surfaceRect.top = 0;
2555 WINPR_ASSERT(surface->width <= UINT16_MAX);
2556 WINPR_ASSERT(surface->height <= UINT16_MAX);
2557 surfaceRect.right = (UINT16)surface->width;
2558 surfaceRect.bottom = (UINT16)surface->height;
2559 if (!region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect))
2560 goto out;
2561
2562 if (server->shareSubRect)
2563 {
2564 if (!region16_intersect_rect(&invalidRegion, &invalidRegion, &(server->subRect)))
2565 goto out;
2566 }
2567
2568 if (region16_is_empty(&invalidRegion))
2569 {
2570 /* No image region need to be updated. Success */
2571 goto out;
2572 }
2573
2574 extents = region16_extents(&invalidRegion);
2575 nXSrc = extents->left;
2576 nYSrc = extents->top;
2577 nWidth = extents->right - extents->left;
2578 nHeight = extents->bottom - extents->top;
2579 pSrcData = surface->data;
2580 nSrcStep = surface->scanline;
2581 SrcFormat = surface->format;
2582
2583 /* Move to new pSrcData / nXSrc / nYSrc according to sub rect */
2584 if (server->shareSubRect)
2585 {
2586 INT32 subX = 0;
2587 INT32 subY = 0;
2588 subX = server->subRect.left;
2589 subY = server->subRect.top;
2590 nXSrc -= subX;
2591 nYSrc -= subY;
2592 WINPR_ASSERT(nXSrc >= 0);
2593 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2594 WINPR_ASSERT(nYSrc >= 0);
2595 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2596 pSrcData = &pSrcData[((UINT16)subY * nSrcStep) + ((UINT16)subX * 4U)];
2597 }
2598
2599 // WLog_INFO(TAG, "shadow_client_send_surface_update: x: %" PRId64 " y: %" PRId64 " width: %"
2600 // PRId64 " height: %" PRId64 " right: %" PRId64 " bottom: %" PRId64, nXSrc, nYSrc, nWidth,
2601 // nHeight, nXSrc + nWidth, nYSrc + nHeight);
2602
2603 if (freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline))
2604 {
2605 if (pStatus->gfxOpened && client->areGfxCapsReady)
2606 {
2607 /* Only codecs that need constant full-frame dimensions (SPS/PPS
2608 * bind the resolution, AV1 the sequence header) must encode the
2609 * whole desktop. rfx and progressive interpret nWidth/nHeight as
2610 * source image dims with the cmd rect as the dirty region, and
2611 * planar/uncompressed encode the cmd rect directly, so those may
2612 * keep the dirty extents. */
2613 const RECTANGLE_16 damage = { .left = WINPR_ASSERTING_INT_CAST(UINT16, nXSrc),
2614 .top = WINPR_ASSERTING_INT_CAST(UINT16, nYSrc),
2615 .right = WINPR_ASSERTING_INT_CAST(UINT16, nXSrc + nWidth),
2616 .bottom =
2617 WINPR_ASSERTING_INT_CAST(UINT16, nYSrc + nHeight) };
2618 const BOOL fullframegfx =
2619#if defined(WITH_GFX_AV1)
2620 shadow_client_av1_enabled(client) ||
2621#endif
2622 freerdp_settings_get_bool(settings, FreeRDP_GfxH264) ||
2623 freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444) ||
2624 freerdp_settings_get_bool(settings, FreeRDP_GfxAVC444v2) ||
2625 (freerdp_settings_get_bool(settings, FreeRDP_RemoteFxCodec) &&
2626 (freerdp_settings_get_uint32(settings, FreeRDP_RemoteFxCodecId) != 0)) ||
2627 freerdp_settings_get_bool(settings, FreeRDP_GfxProgressive);
2628 if (fullframegfx)
2629 {
2630 nWidth = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
2631 nHeight = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
2632 }
2633
2634 /* Create primary surface if have not */
2635 if (!pStatus->gfxSurfaceCreated)
2636 {
2637 /* Only init surface when we have h264 supported */
2638 if (!(ret = shadow_client_rdpgfx_reset_graphic(client)))
2639 goto out;
2640
2641 if (!(ret = shadow_client_rdpgfx_new_surface(client)))
2642 goto out;
2643
2644 pStatus->gfxSurfaceCreated = TRUE;
2645 }
2646
2647 WINPR_ASSERT(nWidth >= 0);
2648 WINPR_ASSERT(nWidth <= UINT16_MAX);
2649 WINPR_ASSERT(nHeight >= 0);
2650 WINPR_ASSERT(nHeight <= UINT16_MAX);
2651 ret = shadow_client_send_surface_gfx(
2652 client, pSrcData, nSrcStep, SrcFormat, fullframegfx ? 0 : (UINT16)nXSrc,
2653 fullframegfx ? 0 : (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight,
2654 (UINT16)surface->width, (UINT16)surface->height, &damage);
2655 }
2656 else
2657 {
2658 ret = TRUE;
2659 }
2660 }
2661 else if (is_surface_command_supported(settings))
2662 {
2663 WINPR_ASSERT(nXSrc >= 0);
2664 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2665 WINPR_ASSERT(nYSrc >= 0);
2666 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2667 WINPR_ASSERT(nWidth >= 0);
2668 WINPR_ASSERT(nWidth <= UINT16_MAX);
2669 WINPR_ASSERT(nHeight >= 0);
2670 WINPR_ASSERT(nHeight <= UINT16_MAX);
2671 ret = shadow_client_send_surface_bits(client, pSrcData, nSrcStep, (UINT16)nXSrc,
2672 (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
2673 }
2674 else
2675 {
2676 WINPR_ASSERT(nXSrc >= 0);
2677 WINPR_ASSERT(nXSrc <= UINT16_MAX);
2678 WINPR_ASSERT(nYSrc >= 0);
2679 WINPR_ASSERT(nYSrc <= UINT16_MAX);
2680 WINPR_ASSERT(nWidth >= 0);
2681 WINPR_ASSERT(nWidth <= UINT16_MAX);
2682 WINPR_ASSERT(nHeight >= 0);
2683 WINPR_ASSERT(nHeight <= UINT16_MAX);
2684 ret = shadow_client_send_bitmap_update(client, pSrcData, nSrcStep, (UINT16)nXSrc,
2685 (UINT16)nYSrc, (UINT16)nWidth, (UINT16)nHeight);
2686 }
2687
2688out:
2689 LeaveCriticalSection(&surface->lock);
2690 region16_uninit(&invalidRegion);
2691 return ret;
2692}
2693
2694/* A size change can go through the graphics pipeline once its surface exists */
2695WINPR_ATTR_NODISCARD
2696static BOOL shadow_client_gfx_can_reset(rdpShadowClient* client, const SHADOW_GFX_STATUS* pStatus)
2697{
2698 WINPR_ASSERT(client);
2699 WINPR_ASSERT(pStatus);
2700
2701 return pStatus->gfxOpened && pStatus->gfxSurfaceCreated && client->areGfxCapsReady &&
2702 client->rdpgfx &&
2703 freerdp_settings_get_bool(client->context.settings, FreeRDP_SupportGraphicsPipeline);
2704}
2705
2716WINPR_ATTR_NODISCARD
2717static BOOL shadow_client_gfx_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2718{
2719 WINPR_ASSERT(client);
2720 WINPR_ASSERT(pStatus);
2721 WINPR_ASSERT(client->server);
2722 WINPR_ASSERT(client->server->surface);
2723
2724 rdpSettings* settings = client->context.settings;
2725 WINPR_ASSERT(settings);
2726
2727 RECTANGLE_16 viewport = {
2728 .left = 0,
2729 .top = 0,
2730 .right = WINPR_ASSERTING_INT_CAST(UINT16, client->server->surface->width),
2731 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, client->server->surface->height)
2732 };
2733 if (client->server->shareSubRect)
2734 {
2735 if (!rectangles_intersection(&viewport, &(client->server->subRect), &viewport))
2736 return FALSE;
2737 }
2738 const UINT32 width = viewport.right - viewport.left;
2739 const UINT32 height = viewport.bottom - viewport.top;
2740
2741 if (!shadow_client_rdpgfx_release_surface(client))
2742 return FALSE;
2743 pStatus->gfxSurfaceCreated = FALSE;
2744
2745 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, width))
2746 return FALSE;
2747 if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, height))
2748 return FALSE;
2749
2750 if (!shadow_client_rdpgfx_reset_graphic(client))
2751 return FALSE;
2752 if (!shadow_client_rdpgfx_new_surface(client))
2753 return FALSE;
2754 pStatus->gfxSurfaceCreated = TRUE;
2755
2756 /* the codecs are sized for the old surface, the next frame is a whole one */
2757 if (shadow_encoder_reset(client->encoder) < 0)
2758 {
2759 WLog_ERR(TAG, "Failed to reset encoder");
2760 return FALSE;
2761 }
2762
2763 EnterCriticalSection(&(client->lock));
2764 region16_clear(&(client->invalidRegion));
2765 LeaveCriticalSection(&(client->lock));
2766 shadow_client_mark_invalid(client, 0, nullptr);
2767
2768 WLog_INFO(TAG, "Client %s resized to %" PRIu32 "x%" PRIu32 " by Reset Graphics",
2769 client->context.peer->hostname, width, height);
2770 return TRUE;
2771}
2772
2780WINPR_ATTR_NODISCARD
2781static BOOL shadow_client_send_resize(rdpShadowClient* client, SHADOW_GFX_STATUS* pStatus)
2782{
2783 rdpContext* context = (rdpContext*)client;
2784 rdpSettings* settings = nullptr;
2785 freerdp_peer* peer = nullptr;
2786
2787 if (!context || !pStatus)
2788 return FALSE;
2789
2790 peer = context->peer;
2791 settings = context->settings;
2792
2793 if (!peer || !settings)
2794 return FALSE;
2795
2801 client->activated = FALSE;
2802
2803 /* Close Gfx surfaces */
2804 if (pStatus->gfxSurfaceCreated)
2805 {
2806 if (!shadow_client_rdpgfx_release_surface(client))
2807 return FALSE;
2808
2809 pStatus->gfxSurfaceCreated = FALSE;
2810 }
2811
2812 /* Send Resize */
2813 if (!shadow_send_desktop_resize(client))
2814 return FALSE;
2815 shadow_reset_desktop_resize(client);
2816
2817 /* Clear my invalidRegion. shadow_client_activate refreshes fullscreen */
2818 EnterCriticalSection(&(client->lock));
2819 region16_clear(&(client->invalidRegion));
2820 LeaveCriticalSection(&(client->lock));
2821 return TRUE;
2822}
2823
2830WINPR_ATTR_NODISCARD
2831static BOOL shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
2832{
2833 UINT32 numRects = 0;
2834 const RECTANGLE_16* rects = nullptr;
2835 rects = region16_rects(region, &numRects);
2836 shadow_client_mark_invalid(client, numRects, rects);
2837 return TRUE;
2838}
2839
2846WINPR_ATTR_NODISCARD
2847static inline BOOL shadow_client_no_surface_update(rdpShadowClient* client,
2848 SHADOW_GFX_STATUS* pStatus)
2849{
2850 rdpShadowServer* server = nullptr;
2851 rdpShadowSurface* surface = nullptr;
2852 WINPR_UNUSED(pStatus);
2853 WINPR_ASSERT(client);
2854 server = client->server;
2855 WINPR_ASSERT(server);
2856 surface = client->inLobby ? server->lobby : server->surface;
2857 EnterCriticalSection(&surface->lock);
2858 const BOOL rc = shadow_client_surface_update(client, &(surface->invalidRegion));
2859 LeaveCriticalSection(&surface->lock);
2860 return rc;
2861}
2862
2863WINPR_ATTR_NODISCARD
2864static int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message)
2865{
2866 rdpContext* context = (rdpContext*)client;
2867
2868 WINPR_ASSERT(message);
2869 WINPR_ASSERT(context);
2870
2871 rdpUpdate* update = context->update;
2872 WINPR_ASSERT(update);
2873
2874 /* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */
2875
2876 switch (message->id)
2877 {
2878 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
2879 {
2880 POINTER_POSITION_UPDATE pointerPosition;
2882 (const SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*)message->wParam;
2883 pointerPosition.xPos = msg->xPos;
2884 pointerPosition.yPos = msg->yPos;
2885
2886 WINPR_ASSERT(client->server);
2887 if (client->server->shareSubRect)
2888 {
2889 pointerPosition.xPos -= client->server->subRect.left;
2890 pointerPosition.yPos -= client->server->subRect.top;
2891 }
2892
2893 if (client->activated)
2894 {
2895 if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY))
2896 {
2897 WINPR_ASSERT(update->pointer);
2898 if (!IFCALLRESULT(TRUE, update->pointer->PointerPosition, context,
2899 &pointerPosition))
2900 return -1;
2901 client->pointerX = msg->xPos;
2902 client->pointerY = msg->yPos;
2903 }
2904 }
2905
2906 break;
2907 }
2908
2909 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
2910 {
2911 POINTER_NEW_UPDATE pointerNew = WINPR_C_ARRAY_INIT;
2912 POINTER_COLOR_UPDATE* pointerColor = WINPR_C_ARRAY_INIT;
2913 POINTER_CACHED_UPDATE pointerCached = WINPR_C_ARRAY_INIT;
2915 (const SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)message->wParam;
2916
2917 WINPR_ASSERT(msg);
2918 pointerNew.xorBpp = 24;
2919 pointerColor = &(pointerNew.colorPtrAttr);
2920 pointerColor->cacheIndex = 0;
2921 pointerColor->hotSpotX = WINPR_ASSERTING_INT_CAST(UINT16, msg->xHot);
2922 pointerColor->hotSpotY = WINPR_ASSERTING_INT_CAST(UINT16, msg->yHot);
2923 pointerColor->width = WINPR_ASSERTING_INT_CAST(UINT16, msg->width);
2924 pointerColor->height = WINPR_ASSERTING_INT_CAST(UINT16, msg->height);
2925 pointerColor->lengthAndMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthAndMask);
2926 pointerColor->lengthXorMask = WINPR_ASSERTING_INT_CAST(UINT16, msg->lengthXorMask);
2927 pointerColor->xorMaskData = msg->xorMaskData;
2928 pointerColor->andMaskData = msg->andMaskData;
2929 pointerCached.cacheIndex = pointerColor->cacheIndex;
2930
2931 if (client->activated)
2932 {
2933 if (client->server->ShowMouseCursor)
2934 {
2935 if (!IFCALLRESULT(TRUE, update->pointer->PointerNew, context, &pointerNew))
2936 return -1;
2937 if (!IFCALLRESULT(TRUE, update->pointer->PointerCached, context,
2938 &pointerCached))
2939 return -1;
2940 }
2941 else
2942 {
2943 POINTER_SYSTEM_UPDATE pointer_system = WINPR_C_ARRAY_INIT;
2944 pointer_system.type = SYSPTR_DEFAULT;
2945 if (!IFCALLRESULT(TRUE, update->pointer->PointerSystem, context,
2946 &pointer_system))
2947 return -1;
2948 }
2949 }
2950
2951 break;
2952 }
2953
2954 case SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID:
2955 {
2957 (const SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES*)message->wParam;
2958
2959 WINPR_ASSERT(msg);
2960
2961 /* Samples that arrive before the client agreed on a format (or when it
2962 * agreed on none) are dropped */
2963 if (client->activated && client->rdpsnd && client->rdpsnd->Activated &&
2964 (client->rdpsnd->selected_client_format < client->rdpsnd->num_client_formats))
2965 {
2966 client->rdpsnd->src_format = msg->audio_format;
2967
2968 const UINT error =
2969 IFCALLRESULT(CHANNEL_RC_OK, client->rdpsnd->SendSamples, client->rdpsnd,
2970 msg->buf, msg->nFrames, msg->wTimestamp);
2971 if (CHANNEL_RC_OK != error)
2972 {
2973 shadow_client_free_queued_message(message);
2974 return -1;
2975 }
2976 }
2977
2978 break;
2979 }
2980
2981 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
2982 {
2984 (const SHADOW_MSG_OUT_AUDIO_OUT_VOLUME*)message->wParam;
2985
2986 if (client->activated && client->rdpsnd && client->rdpsnd->Activated)
2987 {
2988 const UINT error = IFCALLRESULT(CHANNEL_RC_OK, client->rdpsnd->SetVolume,
2989 client->rdpsnd, msg->left, msg->right);
2990 if (CHANNEL_RC_OK != error)
2991 {
2992 shadow_client_free_queued_message(message);
2993 return -1;
2994 }
2995 }
2996
2997 break;
2998 }
2999
3000 default:
3001 WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", message->id);
3002 break;
3003 }
3004
3005 shadow_client_free_queued_message(message);
3006 return 1;
3007}
3008
3009/* Puts the queued channel data on the wire. The client thread and the sound thread both do it,
3010 * one at a time, so that the chunks of a channel keep their order. Only the client thread opens
3011 * channels (autoOpen). */
3012WINPR_ATTR_NODISCARD
3013static BOOL shadow_client_drain_channels(rdpShadowClient* client, BOOL autoOpen)
3014{
3015 WINPR_ASSERT(client);
3016
3017 EnterCriticalSection(&client->vcmLock);
3018 const BOOL rc = WTSVirtualChannelManagerCheckFileDescriptorEx(client->vcm, autoOpen);
3019 LeaveCriticalSection(&client->vcmLock);
3020 return rc;
3021}
3022
3023/* Sends the sound samples and volume as they come. On the client thread they waited for every
3024 * frame to be encoded first (40 to 120 ms a frame with AV2, its key frames 500 to 800 ms), and
3025 * the client ran dry: the sound crackled. */
3026static DWORD WINAPI shadow_client_sound_thread(LPVOID arg)
3027{
3028 rdpShadowClient* client = (rdpShadowClient*)arg;
3029 WINPR_ASSERT(client);
3030 wMessageQueue* queue = client->SoundQueue;
3031 WINPR_ASSERT(queue);
3032 BOOL warned = FALSE;
3033 BOOL broken = FALSE;
3034
3035 while (MessageQueue_Wait(queue))
3036 {
3037 wMessage message = WINPR_C_ARRAY_INIT;
3038 BOOL quit = FALSE;
3039 BOOL queued = FALSE;
3040
3041 while (MessageQueue_Peek(queue, &message, TRUE))
3042 {
3043 if (message.id == WMQ_QUIT)
3044 {
3045 quit = TRUE;
3046 break;
3047 }
3048
3049 /* the connection is gone: drop the sound, the client thread ends the client */
3050 if (broken)
3051 {
3052 shadow_client_free_queued_message(&message);
3053 continue;
3054 }
3055
3056 /* frees the message */
3057 const int rc = shadow_client_subsystem_process_message(client, &message);
3058 if ((rc < 0) && !warned)
3059 {
3060 warned = TRUE;
3061 WLog_WARN(TAG, "sound: the samples or the volume could not be sent");
3062 }
3063 queued = TRUE;
3064 }
3065
3066 /* A failed drain means the connection is gone. Draining on held the channel lock and
3067 * wrote every chunk again into the dead transport, and the client thread waited for
3068 * the lock instead of ending the client. */
3069 if (queued && !broken && !shadow_client_drain_channels(client, FALSE))
3070 {
3071 broken = TRUE;
3072 WLog_DBG(TAG, "sound: the channel data was not sent, no more sound for this client");
3073 }
3074
3075 if (quit)
3076 break;
3077 }
3078
3079 ExitThread(0);
3080 return 0;
3081}
3082
3083static void shadow_client_sound_thread_stop(rdpShadowClient* client)
3084{
3085 WINPR_ASSERT(client);
3086
3087 if (!client->soundThread)
3088 return;
3089
3090 /* fails only without memory; the thread uses the channels, so it must be gone anyway */
3091 if (!MessageQueue_PostQuit(client->SoundQueue, 0))
3092 WLog_ERR(TAG, "sound: cannot ask the sound thread to stop");
3093 (void)WaitForSingleObject(client->soundThread, INFINITE);
3094 (void)CloseHandle(client->soundThread);
3095 client->soundThread = nullptr;
3096}
3097
3098/* A client that has never acknowledged a frame (and did not suspend the acknowledgements) still
3099 * gets one frame this often, so it is not frozen. A client that acknowledges is held at the limit:
3100 * one that stops reading for longer than TcpAckTimeout (9 s) is disconnected by TCP anyway. */
3101#define SHADOW_GFX_ACK_STALL_MS 2000u
3102
3103/* GFX flow control: TRUE when this round's frame must wait. The server sent every damaged frame
3104 * however far the client was behind, and on a slow link the frames queued up in TCP for seconds:
3105 * the client showed old pictures, the sound and the pointer came late. Like xrdp, at most
3106 * maxInFlight frames go out without an acknowledgement; the damage of the rounds in between
3107 * waits in the client's region and goes out in one frame when an acknowledgement comes. */
3108WINPR_ATTR_NODISCARD
3109static BOOL shadow_client_gfx_must_wait(rdpShadowClient* client, const SHADOW_GFX_STATUS* status)
3110{
3111 WINPR_ASSERT(client);
3112 WINPR_ASSERT(status);
3113 rdpShadowEncoder* encoder = client->encoder;
3114 WINPR_ASSERT(encoder);
3115
3116 if ((encoder->maxInFlight == 0) || !status->gfxOpened || !client->areGfxCapsReady ||
3117 !freerdp_settings_get_bool(client->context.settings, FreeRDP_SupportGraphicsPipeline))
3118 return FALSE;
3119
3120 /* 0 when the client suspended its acknowledgements */
3121 const UINT32 inFlight = shadow_encoder_inflight_frames(encoder);
3122 encoder->statsMaxInFlight = MAX(encoder->statsMaxInFlight, inFlight);
3123 if (inFlight < encoder->maxInFlight)
3124 return FALSE;
3125
3126 const UINT64 now = GetTickCount64();
3127 if (!encoder->everAcked && (now - encoder->lastAckTick >= SHADOW_GFX_ACK_STALL_MS))
3128 {
3129 if (!encoder->warnedNoAck)
3130 {
3131 encoder->warnedNoAck = TRUE;
3132 WLog_WARN(TAG,
3133 "gfx: the client acknowledges no frame, one frame every %u ms (%" PRIu32
3134 " in flight)",
3135 SHADOW_GFX_ACK_STALL_MS, inFlight);
3136 }
3137 /* the next one after another stall period */
3138 encoder->lastAckTick = now;
3139 return FALSE;
3140 }
3141 return TRUE;
3142}
3143
3144/* the 5 s line for the flow control, at debug level */
3145static void shadow_client_gfx_stats(rdpShadowClient* client)
3146{
3147 WINPR_ASSERT(client);
3148 rdpShadowEncoder* encoder = client->encoder;
3149 WINPR_ASSERT(encoder);
3150
3151 const UINT64 now = GetTickCount64();
3152 if (now - encoder->statsLogged < 5000)
3153 return;
3154 if (encoder->statsLogged != 0)
3155 WLog_DBG(TAG,
3156 "gfx: at most %" PRIu32 " of %" PRIu32 " frames in flight, %" PRIu64
3157 " round(s) waited",
3158 encoder->statsMaxInFlight, encoder->maxInFlight, encoder->statsHeld);
3159 encoder->statsMaxInFlight = 0;
3160 encoder->statsHeld = 0;
3161 encoder->statsLogged = now;
3162}
3163
3164WINPR_ATTR_NODISCARD
3165static DWORD WINAPI shadow_client_thread(LPVOID arg)
3166{
3167 rdpShadowClient* client = (rdpShadowClient*)arg;
3168 BOOL rc = FALSE;
3169 DWORD status = 0;
3170 wMessage message = WINPR_C_ARRAY_INIT;
3171 wMessage pointerPositionMsg = WINPR_C_ARRAY_INIT;
3172 wMessage pointerAlphaMsg = WINPR_C_ARRAY_INIT;
3173 wMessage audioVolumeMsg = WINPR_C_ARRAY_INIT;
3174 HANDLE ChannelEvent = nullptr;
3175 void* UpdateSubscriber = nullptr;
3176 HANDLE UpdateEvent = nullptr;
3177 freerdp_peer* peer = nullptr;
3178 rdpContext* context = nullptr;
3179 rdpSettings* settings = nullptr;
3180 rdpShadowServer* server = nullptr;
3181 rdpShadowSubsystem* subsystem = nullptr;
3182 wMessageQueue* MsgQueue = nullptr;
3183 /* This should only be visited in client thread */
3184 SHADOW_GFX_STATUS gfxstatus = WINPR_C_ARRAY_INIT;
3185 rdpUpdate* update = nullptr;
3186
3187 WINPR_ASSERT(client);
3188
3189 MsgQueue = client->MsgQueue;
3190 WINPR_ASSERT(MsgQueue);
3191
3192 server = client->server;
3193 WINPR_ASSERT(server);
3194 subsystem = server->subsystem;
3195 context = (rdpContext*)client;
3196 peer = context->peer;
3197 WINPR_ASSERT(peer);
3198 WINPR_ASSERT(peer->context);
3199
3200 settings = peer->context->settings;
3201 WINPR_ASSERT(settings);
3202
3203 peer->Capabilities = shadow_client_capabilities;
3204 peer->PostConnect = shadow_client_post_connect;
3205 peer->Activate = shadow_client_activate;
3206 peer->Logon = shadow_client_logon;
3207 shadow_input_register_callbacks(peer->context->input);
3208
3209 rc = peer->Initialize(peer);
3210 if (!rc)
3211 goto out;
3212
3213 update = peer->context->update;
3214 WINPR_ASSERT(update);
3215
3216 update->RefreshRect = shadow_client_refresh_rect;
3217 update->SuppressOutput = shadow_client_suppress_output;
3218 update->SurfaceFrameAcknowledge = shadow_client_surface_frame_acknowledge;
3219
3220 if ((!client->vcm) || (!subsystem->updateEvent))
3221 goto out;
3222
3223 ChannelEvent = WTSVirtualChannelManagerGetEventHandle(client->vcm);
3224 WINPR_ASSERT(ChannelEvent);
3225
3226 rc = freerdp_settings_set_bool(settings, FreeRDP_UnicodeInput, TRUE);
3227 WINPR_ASSERT(rc);
3228 rc = freerdp_settings_set_bool(settings, FreeRDP_HasHorizontalWheel, TRUE);
3229 WINPR_ASSERT(rc);
3230 rc = freerdp_settings_set_bool(settings, FreeRDP_HasExtendedMouseEvent, TRUE);
3231 WINPR_ASSERT(rc);
3232 rc = freerdp_settings_set_bool(settings, FreeRDP_SupportMonitorLayoutPdu, TRUE);
3233 WINPR_ASSERT(rc);
3234
3235 client->soundThread = CreateThread(nullptr, 0, shadow_client_sound_thread, client, 0, nullptr);
3236 if (!client->soundThread)
3237 {
3238 WLog_ERR(TAG, "Failed to start the sound thread");
3239 goto fail;
3240 }
3241
3242 while (1)
3243 {
3244 HANDLE events[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
3245 DWORD nCount = 0;
3246
3247 /* The subsystem and all other clients wait until every subscriber has
3248 * consumed the current frame. Only subscribe once the connection sequence
3249 * is done: peer->CheckFileDescriptor blocks this thread during the TLS
3250 * and NLA handshake for as long as the (not yet authenticated) peer wants,
3251 * and before activation there is nothing to send anyway. */
3252 if (!UpdateSubscriber && client->activated)
3253 {
3254 UpdateSubscriber = shadow_multiclient_get_subscriber(subsystem->updateEvent);
3255
3256 if (!UpdateSubscriber)
3257 goto fail;
3258
3259 UpdateEvent = shadow_multiclient_getevent(UpdateSubscriber);
3260 WINPR_ASSERT(UpdateEvent);
3261
3262 /* The full screen refresh requested by shadow_client_activate may
3263 * already have been published without us, request it again */
3264 if (!shadow_client_refresh_request(client))
3265 goto fail;
3266 }
3267
3268 if (UpdateEvent)
3269 events[nCount++] = UpdateEvent;
3270 {
3271 DWORD tmp = peer->GetEventHandles(peer, &events[nCount], 64 - nCount);
3272
3273 if (tmp == 0)
3274 {
3275 WLog_ERR(TAG, "Failed to get FreeRDP transport event handles");
3276 goto fail;
3277 }
3278
3279 nCount += tmp;
3280 }
3281 events[nCount++] = ChannelEvent;
3282 events[nCount++] = MessageQueue_Event(MsgQueue);
3283
3284#if defined(CHANNEL_RDPGFX_SERVER)
3285 HANDLE gfxevent = rdpgfx_server_get_event_handle(client->rdpgfx);
3286
3287 if (gfxevent)
3288 events[nCount++] = gfxevent;
3289#endif
3290
3291 /* a frame that waits for an acknowledgement also goes out after a stall */
3292 const DWORD timeout = MIN(client->encoder->gfxHeld ? 100 : INFINITE,
3293 shadow_client_autodetect_timeout(client));
3294 status = WaitForMultipleObjects(nCount, events, FALSE, timeout);
3295
3296 if (status == WAIT_FAILED)
3297 goto fail;
3298
3299 if (UpdateEvent && (WaitForSingleObject(UpdateEvent, 0) == WAIT_OBJECT_0))
3300 {
3301 /* The UpdateEvent means to start sending current frame. It is
3302 * triggered from subsystem implementation and it should ensure
3303 * that the screen and primary surface meta data (width, height,
3304 * scanline, invalid region, etc) is not changed until it is reset
3305 * (at shadow_multiclient_consume). As best practice, subsystem
3306 * implementation should invoke shadow_subsystem_frame_update which
3307 * triggers the event and then wait for completion */
3308 if (client->activated && !client->suppressOutput)
3309 {
3310 /* Send screen update or resize to this client */
3311
3312 /* Check resize */
3313 if (shadow_client_recalc_desktop_size(client))
3314 {
3315 if (shadow_client_gfx_can_reset(client, &gfxstatus))
3316 {
3317 /* the new size and this update's frame for it, in that order */
3318 if (!shadow_client_gfx_resize(client, &gfxstatus))
3319 {
3320 WLog_ERR(TAG, "Failed to resize the graphics pipeline");
3321 break;
3322 }
3323 if (!shadow_client_send_surface_update(client, &gfxstatus))
3324 {
3325 WLog_ERR(TAG, "Failed to send surface update");
3326 break;
3327 }
3328 client->encoder->gfxHeld = FALSE;
3329 }
3330 /* Screen size changed, do resize */
3331 else if (!shadow_client_send_resize(client, &gfxstatus))
3332 {
3333 WLog_ERR(TAG, "Failed to send resize message");
3334 break;
3335 }
3336 }
3337 else if (shadow_client_gfx_must_wait(client, &gfxstatus))
3338 {
3339 /* the client is behind: keep the damage for when it caught up */
3340 if (!shadow_client_no_surface_update(client, &gfxstatus))
3341 {
3342 WLog_ERR(TAG, "Failed to handle surface update");
3343 break;
3344 }
3345 client->encoder->gfxHeld = TRUE;
3346 client->encoder->statsHeld++;
3347 }
3348 else
3349 {
3350 /* Send frame */
3351 if (!shadow_client_send_surface_update(client, &gfxstatus))
3352 {
3353 WLog_ERR(TAG, "Failed to send surface update");
3354 break;
3355 }
3356 client->encoder->gfxHeld = FALSE;
3357 }
3358 }
3359 else
3360 {
3361 /* Our client don't receive graphic updates. Just save the invalid region */
3362 if (!shadow_client_no_surface_update(client, &gfxstatus))
3363 {
3364 WLog_ERR(TAG, "Failed to handle surface update");
3365 break;
3366 }
3367 }
3368
3369 /*
3370 * The return value of shadow_multiclient_consume is whether or not
3371 * the subscriber really consumes the event. It's not cared currently.
3372 */
3373 (void)shadow_multiclient_consume(UpdateSubscriber);
3374 }
3375
3376 WINPR_ASSERT(peer->CheckFileDescriptor);
3377 if (!peer->CheckFileDescriptor(peer))
3378 {
3379 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
3380 goto fail;
3381 }
3382
3383 if (!shadow_client_autodetect_poll(client))
3384 {
3385 WLog_ERR(TAG, "Failed to send an RTT Measure Request");
3386 goto fail;
3387 }
3388
3389 if (client->activated &&
3390 WTSVirtualChannelManagerIsChannelJoined(client->vcm, DRDYNVC_SVC_CHANNEL_NAME))
3391 {
3392 switch (WTSVirtualChannelManagerGetDrdynvcState(client->vcm))
3393 {
3394 /* Dynamic channel status may have been changed after processing */
3395 case DRDYNVC_STATE_NONE:
3396
3397 /* Call this routine to Initialize drdynvc channel */
3398 if (!shadow_client_drain_channels(client, TRUE))
3399 {
3400 WLog_ERR(TAG, "Failed to initialize drdynvc channel");
3401 goto fail;
3402 }
3403
3404 break;
3405
3406 case DRDYNVC_STATE_READY:
3407#if defined(CHANNEL_AUDIN_SERVER)
3408 if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
3409 {
3410 if (!IFCALLRESULT(FALSE, client->audin->Open, client->audin))
3411 {
3412 WLog_ERR(TAG, "Failed to initialize audin channel");
3413 goto fail;
3414 }
3415 }
3416#endif
3417
3418 /* Init RDPGFX dynamic channel */
3419 if (freerdp_settings_get_bool(settings, FreeRDP_SupportGraphicsPipeline) &&
3420 client->rdpgfx && !gfxstatus.gfxOpened)
3421 {
3422 client->rdpgfx->FrameAcknowledge = shadow_client_rdpgfx_frame_acknowledge;
3423 client->rdpgfx->CapsAdvertise = shadow_client_rdpgfx_caps_advertise;
3424
3425 if (!client->rdpgfx->Open(client->rdpgfx))
3426 {
3427 WLog_WARN(TAG, "Failed to open GraphicsPipeline");
3428 if (!freerdp_settings_set_bool(settings,
3429 FreeRDP_SupportGraphicsPipeline, FALSE))
3430 goto fail;
3431 }
3432 else
3433 {
3434 gfxstatus.gfxOpened = TRUE;
3435 WLog_INFO(TAG, "Gfx Pipeline Opened");
3436 }
3437 }
3438
3439 break;
3440
3441 default:
3442 break;
3443 }
3444 }
3445
3446 if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0)
3447 {
3448 if (!shadow_client_drain_channels(client, TRUE))
3449 {
3450 WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure");
3451 goto fail;
3452 }
3453 }
3454
3455#if defined(CHANNEL_RDPGFX_SERVER)
3456 if (gfxevent)
3457 {
3458 if (WaitForSingleObject(gfxevent, 0) == WAIT_OBJECT_0)
3459 {
3460 const UINT error = rdpgfx_server_handle_messages(client->rdpgfx);
3461 if (error != CHANNEL_RC_OK)
3462 goto fail;
3463 }
3464 }
3465#endif
3466
3467 /* an acknowledgement (or a stall) let the waiting damage go: one frame of the surface as
3468 * it is now, not the frames that were skipped */
3469 if (client->encoder->gfxHeld && client->activated && !client->suppressOutput &&
3470 !shadow_client_gfx_must_wait(client, &gfxstatus))
3471 {
3472 if (!shadow_client_send_surface_update(client, &gfxstatus))
3473 {
3474 WLog_ERR(TAG, "Failed to send surface update");
3475 goto fail;
3476 }
3477 client->encoder->gfxHeld = FALSE;
3478 }
3479 if (client->activated)
3480 shadow_client_gfx_stats(client);
3481
3482 if (WaitForSingleObject(MessageQueue_Event(MsgQueue), 0) == WAIT_OBJECT_0)
3483 {
3484 /* Drain messages. Pointer update could be accumulated. */
3485 pointerPositionMsg.id = 0;
3486 pointerPositionMsg.Free = nullptr;
3487 pointerAlphaMsg.id = 0;
3488 pointerAlphaMsg.Free = nullptr;
3489 audioVolumeMsg.id = 0;
3490 audioVolumeMsg.Free = nullptr;
3491
3492 while (MessageQueue_Peek(MsgQueue, &message, TRUE))
3493 {
3494 if (message.id == WMQ_QUIT)
3495 {
3496 break;
3497 }
3498
3499 switch (message.id)
3500 {
3501 case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
3502 /* Abandon previous message */
3503 shadow_client_free_queued_message(&pointerPositionMsg);
3504 pointerPositionMsg = message;
3505 break;
3506
3507 case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
3508 /* Abandon previous message */
3509 shadow_client_free_queued_message(&pointerAlphaMsg);
3510 pointerAlphaMsg = message;
3511 break;
3512
3513 case SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID:
3514 /* Abandon previous message */
3515 shadow_client_free_queued_message(&audioVolumeMsg);
3516 audioVolumeMsg = message;
3517 break;
3518
3519 default:
3520 if (!shadow_client_subsystem_process_message(client, &message))
3521 goto fail;
3522 break;
3523 }
3524 }
3525
3526 if (message.id == WMQ_QUIT)
3527 {
3528 /* Release stored message */
3529 shadow_client_free_queued_message(&pointerPositionMsg);
3530 shadow_client_free_queued_message(&pointerAlphaMsg);
3531 shadow_client_free_queued_message(&audioVolumeMsg);
3532 goto fail;
3533 }
3534 else
3535 {
3536 /* Process accumulated messages if needed */
3537 if (pointerPositionMsg.id)
3538 {
3539 if (!shadow_client_subsystem_process_message(client, &pointerPositionMsg))
3540 goto fail;
3541 }
3542
3543 if (pointerAlphaMsg.id)
3544 {
3545 if (!shadow_client_subsystem_process_message(client, &pointerAlphaMsg))
3546 goto fail;
3547 }
3548
3549 if (audioVolumeMsg.id)
3550 {
3551 if (!shadow_client_subsystem_process_message(client, &audioVolumeMsg))
3552 goto fail;
3553 }
3554 }
3555 }
3556 }
3557
3558fail:
3559
3560 /* The sound thread uses the channels: stop it first */
3561 shadow_client_sound_thread_stop(client);
3562
3563 /* Free channels early because we establish channels in post connect */
3564#if defined(CHANNEL_AUDIN_SERVER)
3565 if (client->audin && !IFCALLRESULT(TRUE, client->audin->IsOpen, client->audin))
3566 {
3567 if (!IFCALLRESULT(FALSE, client->audin->Close, client->audin))
3568 {
3569 WLog_WARN(TAG, "AUDIN shutdown failure!");
3570 }
3571 }
3572#endif
3573
3574 if (gfxstatus.gfxOpened)
3575 {
3576 if (gfxstatus.gfxSurfaceCreated)
3577 {
3578 if (!shadow_client_rdpgfx_release_surface(client))
3579 WLog_WARN(TAG, "GFX release surface failure!");
3580 }
3581
3582 WINPR_ASSERT(client->rdpgfx);
3583 WINPR_ASSERT(client->rdpgfx->Close);
3584 rc = client->rdpgfx->Close(client->rdpgfx);
3585 WINPR_ASSERT(rc);
3586 }
3587
3588 shadow_client_channels_free(client);
3589
3590 if (UpdateSubscriber)
3591 {
3592 shadow_multiclient_release_subscriber(UpdateSubscriber);
3593 UpdateSubscriber = nullptr;
3594 }
3595
3596 if (peer->connected && subsystem->ClientDisconnect)
3597 {
3598 subsystem->ClientDisconnect(subsystem, client);
3599 }
3600
3601out:
3602 /* however the client went, no key it held stays down on the shared desktop */
3603 if (!shadow_input_release_keys(client))
3604 WLog_WARN(TAG, "not every key the client held could be released");
3605 WINPR_ASSERT(peer->Disconnect);
3606 peer->Disconnect(peer);
3607 freerdp_peer_context_free(peer);
3608 freerdp_peer_free(peer);
3609 ExitThread(0);
3610 return 0;
3611}
3612
3613BOOL shadow_client_accepted(freerdp_listener* listener, freerdp_peer* peer)
3614{
3615 rdpShadowClient* client = nullptr;
3616 rdpShadowServer* server = nullptr;
3617
3618 if (!listener || !peer)
3619 return FALSE;
3620
3621 server = (rdpShadowServer*)listener->info;
3622 WINPR_ASSERT(server);
3623
3624 peer->ContextExtra = (void*)server;
3625 peer->ContextSize = sizeof(rdpShadowClient);
3626 peer->ContextNew = shadow_client_context_new;
3627 peer->ContextFree = shadow_client_context_free;
3628
3629 if (!freerdp_peer_context_new_ex(peer, server->settings))
3630 return FALSE;
3631
3632 client = (rdpShadowClient*)peer->context;
3633 WINPR_ASSERT(client);
3634
3635 if (!(client->thread = CreateThread(nullptr, 0, shadow_client_thread, client, 0, nullptr)))
3636 {
3637 freerdp_peer_context_free(peer);
3638 return FALSE;
3639 }
3640 else
3641 {
3642 /* Close the thread handle to make it detached. */
3643 (void)CloseHandle(client->thread);
3644 client->thread = nullptr;
3645 }
3646
3647 return TRUE;
3648}
3649
3650static void shadow_msg_out_addref(wMessage* message)
3651{
3652 SHADOW_MSG_OUT* msg = nullptr;
3653
3654 WINPR_ASSERT(message);
3655 msg = (SHADOW_MSG_OUT*)message->wParam;
3656 WINPR_ASSERT(msg);
3657
3658 InterlockedIncrement(&(msg->refCount));
3659}
3660
3661static void shadow_msg_out_release(wMessage* message)
3662{
3663 SHADOW_MSG_OUT* msg = nullptr;
3664
3665 WINPR_ASSERT(message);
3666 msg = (SHADOW_MSG_OUT*)message->wParam;
3667 WINPR_ASSERT(msg);
3668
3669 if (InterlockedDecrement(&(msg->refCount)) <= 0)
3670 {
3671 IFCALL(msg->Free, message->id, msg);
3672 }
3673}
3674
3675WINPR_ATTR_NODISCARD
3676static BOOL shadow_client_dispatch_msg(rdpShadowClient* client, wMessage* message)
3677{
3678 if (!client || !message)
3679 return FALSE;
3680
3681 /* Add reference when it is posted */
3682 shadow_msg_out_addref(message);
3683
3684 /* the sound has a thread of its own: see shadow_client_sound_thread */
3685 wMessageQueue* queue = client->MsgQueue;
3686 if ((message->id == SHADOW_MSG_OUT_AUDIO_OUT_SAMPLES_ID) ||
3687 (message->id == SHADOW_MSG_OUT_AUDIO_OUT_VOLUME_ID))
3688 queue = client->SoundQueue;
3689
3690 WINPR_ASSERT(queue);
3691 if (MessageQueue_Dispatch(queue, message))
3692 return TRUE;
3693 else
3694 {
3695 /* Release the reference since post failed */
3696 shadow_msg_out_release(message);
3697 return FALSE;
3698 }
3699}
3700
3701BOOL shadow_client_post_msg(rdpShadowClient* client, void* context, UINT32 type,
3702 SHADOW_MSG_OUT* msg, void* lParam)
3703{
3704 wMessage message = WINPR_C_ARRAY_INIT;
3705 message.context = context;
3706 message.id = type;
3707 message.wParam = (void*)msg;
3708 message.lParam = lParam;
3709 message.Free = shadow_msg_out_release;
3710 return shadow_client_dispatch_msg(client, &message);
3711}
3712
3713int shadow_client_boardcast_msg(rdpShadowServer* server, void* context, UINT32 type,
3714 SHADOW_MSG_OUT* msg, void* lParam)
3715{
3716 wMessage message = WINPR_C_ARRAY_INIT;
3717 int count = 0;
3718
3719 WINPR_ASSERT(server);
3720 WINPR_ASSERT(msg);
3721
3722 message.context = context;
3723 message.id = type;
3724 message.wParam = (void*)msg;
3725 message.lParam = lParam;
3726 message.Free = shadow_msg_out_release;
3727 /* First add reference as we reference it in this function.
3728 * Therefore it would not be free'ed during post. */
3729 shadow_msg_out_addref(&message);
3730
3731 WINPR_ASSERT(server->clients);
3732 ArrayList_Lock(server->clients);
3733
3734 for (size_t index = 0; index < ArrayList_Count(server->clients); index++)
3735 {
3736 rdpShadowClient* client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
3737
3738 if (shadow_client_dispatch_msg(client, &message))
3739 {
3740 count++;
3741 }
3742 }
3743
3744 ArrayList_Unlock(server->clients);
3745 /* Release the reference for this function */
3746 shadow_msg_out_release(&message);
3747 return count;
3748}
3749
3750int shadow_client_boardcast_quit(rdpShadowServer* server, int nExitCode)
3751{
3752 wMessageQueue* queue = nullptr;
3753 int count = 0;
3754
3755 WINPR_ASSERT(server);
3756 WINPR_ASSERT(server->clients);
3757
3758 ArrayList_Lock(server->clients);
3759
3760 for (size_t index = 0; index < ArrayList_Count(server->clients); index++)
3761 {
3762 queue = ((rdpShadowClient*)ArrayList_GetItem(server->clients, index))->MsgQueue;
3763
3764 if (MessageQueue_PostQuit(queue, nExitCode))
3765 {
3766 count++;
3767 }
3768 }
3769
3770 ArrayList_Unlock(server->clients);
3771 return count;
3772}
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.
Definition rfx.h:44
This struct contains function pointer to initialize/free objects.
Definition collections.h:52