GUACAMOLE-377: Support for RDPGFX.

This commit is contained in:
Michael Jumper 2021-07-05 16:54:31 -07:00
parent 81300052e0
commit c469300941
5 changed files with 197 additions and 9 deletions

View File

@ -57,6 +57,7 @@ libguac_client_rdp_la_SOURCES = \
channels/rdpdr/rdpdr-printer.c \ channels/rdpdr/rdpdr-printer.c \
channels/rdpdr/rdpdr.c \ channels/rdpdr/rdpdr.c \
channels/rdpei.c \ channels/rdpei.c \
channels/rdpgfx.c \
channels/rdpsnd/rdpsnd-messages.c \ channels/rdpsnd/rdpsnd-messages.c \
channels/rdpsnd/rdpsnd.c \ channels/rdpsnd/rdpsnd.c \
client.c \ client.c \
@ -103,6 +104,7 @@ noinst_HEADERS = \
channels/rdpdr/rdpdr-printer.h \ channels/rdpdr/rdpdr-printer.h \
channels/rdpdr/rdpdr.h \ channels/rdpdr/rdpdr.h \
channels/rdpei.h \ channels/rdpei.h \
channels/rdpgfx.h \
channels/rdpsnd/rdpsnd-messages.h \ channels/rdpsnd/rdpsnd-messages.h \
channels/rdpsnd/rdpsnd.h \ channels/rdpsnd/rdpsnd.h \
client.h \ client.h \

View File

@ -0,0 +1,122 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "channels/rdpgfx.h"
#include "plugins/channels.h"
#include "rdp.h"
#include "settings.h"
#include <freerdp/client/rdpgfx.h>
#include <freerdp/freerdp.h>
#include <freerdp/gdi/gfx.h>
#include <freerdp/event.h>
#include <guacamole/client.h>
#include <stdlib.h>
#include <string.h>
/**
* Callback which associates handlers specific to Guacamole with the
* RdpgfxClientContext instance allocated by FreeRDP to deal with received
* RDPGFX (Graphics Pipeline) messages.
*
* This function is called whenever a channel connects via the PubSub event
* system within FreeRDP, but only has any effect if the connected channel is
* the RDPGFX channel. This specific callback is registered with the
* PubSub system of the relevant rdpContext when guac_rdp_rdpgfx_load_plugin() is
* called.
*
* @param context
* The rdpContext associated with the active RDP session.
*
* @param e
* Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP.
*/
static void guac_rdp_rdpgfx_channel_connected(rdpContext* context,
ChannelConnectedEventArgs* e) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
/* Ignore connection event if it's not for the RDPGFX channel */
if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) != 0)
return;
/* Init GDI-backed support for the Graphics Pipeline */
RdpgfxClientContext* rdpgfx = (RdpgfxClientContext*) e->pInterface;
rdpGdi* gdi = context->gdi;
if (!gdi_graphics_pipeline_init(gdi, rdpgfx))
guac_client_log(client, GUAC_LOG_WARNING, "Rendering backend for RDPGFX "
"channel could not be loaded. Graphics may not render at all!");
else
guac_client_log(client, GUAC_LOG_DEBUG, "RDPGFX channel will be used for "
"the RDP Graphics Pipeline Extension.");
}
/**
* Callback which handles any RDPGFX cleanup specific to Guacamole.
*
* This function is called whenever a channel disconnects via the PubSub event
* system within FreeRDP, but only has any effect if the disconnected channel
* is the RDPGFX channel. This specific callback is registered with the PubSub
* system of the relevant rdpContext when guac_rdp_rdpgfx_load_plugin() is
* called.
*
* @param context
* The rdpContext associated with the active RDP session.
*
* @param e
* Event-specific arguments, mainly the name of the channel, and a
* reference to the associated plugin loaded for that channel by FreeRDP.
*/
static void guac_rdp_rdpgfx_channel_disconnected(rdpContext* context,
ChannelDisconnectedEventArgs* e) {
guac_client* client = ((rdp_freerdp_context*) context)->client;
/* Ignore disconnection event if it's not for the RDPGFX channel */
if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) != 0)
return;
/* Un-init GDI-backed support for the Graphics Pipeline */
RdpgfxClientContext* rdpgfx = (RdpgfxClientContext*) e->pInterface;
rdpGdi* gdi = context->gdi;
gdi_graphics_pipeline_uninit(gdi, rdpgfx);
guac_client_log(client, GUAC_LOG_DEBUG, "RDPGFX channel support unloaded.");
}
void guac_rdp_rdpgfx_load_plugin(rdpContext* context) {
/* Subscribe to and handle channel connected events */
PubSub_SubscribeChannelConnected(context->pubSub,
(pChannelConnectedEventHandler) guac_rdp_rdpgfx_channel_connected);
/* Subscribe to and handle channel disconnected events */
PubSub_SubscribeChannelDisconnected(context->pubSub,
(pChannelDisconnectedEventHandler) guac_rdp_rdpgfx_channel_disconnected);
/* Add "rdpgfx" channel */
guac_freerdp_dynamic_channel_collection_add(context->settings, "rdpgfx", NULL);
}

View File

@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUAC_RDP_CHANNELS_RDPGFX_H
#define GUAC_RDP_CHANNELS_RDPGFX_H
#include "settings.h"
#include <freerdp/client/rdpgfx.h>
#include <freerdp/freerdp.h>
#include <guacamole/client.h>
/**
* Adds FreeRDP's "rdpgfx" plugin to the list of dynamic virtual channel plugins
* to be loaded by FreeRDP's "drdynvc" plugin. The context of the plugin will
* automatically be assicated with the guac_rdp_rdpgfx instance pointed to by the
* current guac_rdp_client. The plugin will only be loaded once the "drdynvc"
* plugin is loaded. The "rdpgfx" plugin ultimately adds support for the RDP
* Graphics Pipeline Extension.
*
* If failures occur, messages noting the specifics of those failures will be
* logged.
*
* This MUST be called within the PreConnect callback of the freerdp instance
* for Graphics Pipeline support to be loaded.
*
* @param context
* The rdpContext associated with the active RDP session.
*/
void guac_rdp_rdpgfx_load_plugin(rdpContext* context);
#endif

View File

@ -28,6 +28,7 @@
#include "channels/rail.h" #include "channels/rail.h"
#include "channels/rdpdr/rdpdr.h" #include "channels/rdpdr/rdpdr.h"
#include "channels/rdpei.h" #include "channels/rdpei.h"
#include "channels/rdpgfx.h"
#include "channels/rdpsnd/rdpsnd.h" #include "channels/rdpsnd/rdpsnd.h"
#include "client.h" #include "client.h"
#include "color.h" #include "color.h"
@ -137,15 +138,6 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
} }
/* Load plugin providing Dynamic Virtual Channel support, if required */
if (instance->settings->SupportDynamicChannels &&
guac_freerdp_channels_load_plugin(context, "drdynvc",
instance->settings)) {
guac_client_log(client, GUAC_LOG_WARNING,
"Failed to load drdynvc plugin. Display update and audio "
"input support will be disabled.");
}
/* Init FreeRDP internal GDI implementation */ /* Init FreeRDP internal GDI implementation */
if (!gdi_init(instance, guac_rdp_get_native_pixel_format(FALSE))) if (!gdi_init(instance, guac_rdp_get_native_pixel_format(FALSE)))
return FALSE; return FALSE;
@ -204,6 +196,18 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
offscreen_cache_register_callbacks(instance->update); offscreen_cache_register_callbacks(instance->update);
palette_cache_register_callbacks(instance->update); palette_cache_register_callbacks(instance->update);
/* Load "rdpgfx" plugin for Graphics Pipeline Extension */
guac_rdp_rdpgfx_load_plugin(context);
/* Load plugin providing Dynamic Virtual Channel support, if required */
if (instance->settings->SupportDynamicChannels &&
guac_freerdp_channels_load_plugin(context, "drdynvc",
instance->settings)) {
guac_client_log(client, GUAC_LOG_WARNING,
"Failed to load drdynvc plugin. Display update and audio "
"input support will be disabled.");
}
return TRUE; return TRUE;
} }

View File

@ -1397,6 +1397,17 @@ void guac_rdp_push_settings(guac_client* client,
/* Explicitly set flag value */ /* Explicitly set flag value */
rdp_settings->PerformanceFlags = guac_rdp_get_performance_flags(guac_settings); rdp_settings->PerformanceFlags = guac_rdp_get_performance_flags(guac_settings);
rdp_settings->SupportGraphicsPipeline = TRUE;
rdp_settings->RemoteFxCodec = TRUE;
/* Required for RemoteFX / Graphics Pipeline */
rdp_settings->FastPathOutput = TRUE;
rdp_settings->FrameMarkerCommandEnabled = TRUE;
rdp_settings->ColorDepth = 32;
rdp_settings->SoftwareGdi = TRUE;
/*rdp_settings->GfxH264 = TRUE;
rdp_settings->GfxAVC444 = TRUE;*/
/* Set individual flags - some FreeRDP versions overwrite the above */ /* Set individual flags - some FreeRDP versions overwrite the above */
rdp_settings->AllowFontSmoothing = guac_settings->font_smoothing_enabled; rdp_settings->AllowFontSmoothing = guac_settings->font_smoothing_enabled;
rdp_settings->DisableWallpaper = !guac_settings->wallpaper_enabled; rdp_settings->DisableWallpaper = !guac_settings->wallpaper_enabled;