Skip to main content
Virtual channels extend the RDP protocol with optional capabilities — clipboard, audio, device redirection, graphics pipeline, and more. FreeRDP implements them as loadable plugins that communicate with the core via a well-defined C interface.

Static vs Dynamic Virtual Channels

Static virtual channels are negotiated in the GCC Conference Create data blocks during connection setup. Each channel gets a fixed slot in the MCS channel table identified by a name up to 8 characters long (e.g. cliprdr, rdpsnd, rdpdr).
  • Maximum of 31 static channels per connection.
  • Channel names are exchanged in CS_NET / SC_NET GCC blocks.
  • The low-level send/receive callbacks are freerdp::SendChannelData / freerdp::ReceiveChannelData.
  • Plugin entry point convention: <name>_DVCPluginEntry for DVC plugins, VirtualChannelEntryEx for SVCs.
The CLIPRDR_SVC_CHANNEL_NAME ("cliprdr"), DRDYNVC_SVC_CHANNEL_NAME ("drdynvc") constants in the channel headers define the exact negotiation names.

Plugin Loading Mechanism

Channel plugins are loaded in the LoadChannels callback on the freerdp instance. The channel manager (rdpChannels) uses the addin loader to find shared libraries by name.
1

Register via settings

Static channels are added to the settings channel collection before connecting:
ADDIN_ARGV* args = freerdp_addin_argv_new(1, (const char*[]){ "cliprdr" });
freerdp_static_channel_collection_add(settings, args);

/* Dynamic channels: */
ADDIN_ARGV* dvc_args = freerdp_addin_argv_new(1, (const char*[]){ "rdpgfx" });
freerdp_dynamic_channel_collection_add(settings, dvc_args);
2

LoadChannels callback fires

freerdp::LoadChannels is called (possibly multiple times on redirect). The default implementation in libfreerdp-client iterates freerdp_static_channel_collection_find() and freerdp_dynamic_channel_collection_find() and calls freerdp_channels_attach().
3

Channel attach / detach

freerdp_channels_attach(instance);   /* load plugins and register with MCS */
freerdp_channels_detach(instance);   /* unload plugins */
4

Runtime channel handles

Channel contexts are stored in rdpChannelHandles (struct rdp_channel_handles) which holds two wListDictionary maps — one for init-phase handles and one for open-phase handles — keyed by channel name.

Built-in Channels

Type: SVC | Name: cliprdr | Header: include/freerdp/channels/cliprdr.hImplements MS-RDPECLIP. Synchronises clipboard content (text, images, files) between client and server. Supports the full format negotiation and file clipboard extension.
Type: SVC | Name: rdpsnd | Header: include/freerdp/channels/rdpsnd.hImplements MS-RDPEA (Remote Desktop Protocol: Audio Output Virtual Channel Extension). Streams PCM/encoded audio from the server to the client. The client side uses OS audio backends (PulseAudio, ALSA, macOS CoreAudio, etc.) via audin/rdpsnd backend plugins.
Type: DVC | Header: include/freerdp/channels/audin.hCaptures microphone audio on the client and forwards it to the server (MS-RDPEAI).
Type: SVC | Name: rdpdr | Header: include/freerdp/channels/rdpdr.hImplements MS-RDPEFS. The parent channel for all device redirection. Sub-protocols include:
  • drive — filesystem/drive redirection (channels/drive/)
  • printer — printer redirection (channels/printer/)
  • serial — serial port redirection (channels/serial/)
  • parallel — parallel port redirection (channels/parallel/)
  • smartcard — smartcard redirection (channels/smartcard/)
Type: SVC | Name: drdynvc | Header: include/freerdp/channels/drdynvc.hThe carrier channel for all DVCs (MS-RDPEDYC). Implements CREATE_REQUEST_PDU, DATA_PDU, CLOSE_REQUEST_PDU, and soft-sync PDUs.
Type: DVC | Name: rdpgfx / Microsoft::Windows::RDS::Graphics | Header: include/freerdp/channels/rdpgfx.hImplements MS-RDPEGFX (Windows 8+). Provides the modern graphics pipeline with surface commands, frame framing, H.264/AVC, RemoteFX Progressive codec, ClearCodec, and explicit surface management. See Codecs for details.
Type: DVC | Header: include/freerdp/channels/rdpei.hImplements MS-RDPEI: multi-touch and pen input forwarding from client to server.
Type: DVC | Header: include/freerdp/channels/urbdrc.hImplements MS-RDPEUSB. Forwards USB devices over the DVC using libusb on the client side.
Type: SVC (inside rdpdr) | Header: include/freerdp/channels/scard.hImplements MS-RDPESC. Forwards PCSC / WinSCard API calls from the server to the client’s physical smartcard reader.
Type: SVC | Header: include/freerdp/channels/rail.hImplements MS-RDPERP (RemoteApp). Individual server-side windows are presented as native client windows.
Type: DVC | Header: include/freerdp/channels/disp.hImplements MS-RDPEDISP. Allows the client to dynamically resize the desktop or change monitor layout without reconnecting.
Type: DVC | Header: include/freerdp/channels/geometry.hCarries geometry information for optimized video (MS-RDPEVOR) – used together with the video channel.
Type: DVC | Header: include/freerdp/channels/video.hImplements MS-RDPEVOR. Delivers H.264-encoded video streams for specific surfaces.
Type: SVC | Header: include/freerdp/channels/encomsp.hImplements MS-RDPEMC. Supports desktop-sharing / collaboration scenarios.
Type: SVC | Header: include/freerdp/channels/remdesk.hImplements MS-RDPERA. Remote Assistance channel for helper-assisted sessions.
Type: DVC | Header: include/freerdp/channels/rdpecam.hImplements MS-RDPECAM. Redirects client camera devices to the remote session.
Type: DVC | Header: include/freerdp/channels/echo.hDiagnostic loopback channel (MS-RDPEECO).
Type: DVC | Header: include/freerdp/channels/telemetry.hCollects connection telemetry data (MS-RDPET).
Type: DVC | Header: include/freerdp/channels/ainput.hExtended pointer and input events beyond the core input channel.
Type: DVC | Header: include/freerdp/channels/location.hRedirects client GPS/location data to the remote session.
Type: DVC | Header: include/freerdp/channels/rdpear.hImplements MS-RDPEAR: redirects authentication package calls (Kerberos, NTLM) from server to client for credential delegation.

Retrieving a Channel Context at Runtime

Once a DVC plugin is loaded and the channel is open, the client context pointer is published via a channel event. The common pattern using rdpClientContext (include/freerdp/client.h) stores well-known contexts in fixed offset fields:
/* rdpClientContext embeds rdpContext as its first member */
struct rdp_client_context
{
    rdpContext context;
    HANDLE     thread;               /* offset 0 */
    AInputClientContext*  ainput;    /* offset 1 - if CHANNEL_AINPUT_CLIENT */
    RdpeiClientContext*   rdpei;     /* offset 2 - if CHANNEL_RDPEI_CLIENT  */
    /* ... */
    EncomspClientContext* encomsp;   /* offset 6 - if CHANNEL_ENCOMSP_CLIENT */
    /* ... */
};
For other channels, subscribe to the ChannelConnected pub/sub event on context->pubSub:
PubSub_SubscribeChannelConnected(context->pubSub, on_channel_connected);

static void on_channel_connected(void* context, const ChannelConnectedEventArgs* e)
{
    if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0)
    {
        RdpgfxClientContext* gfx = (RdpgfxClientContext*)e->pInterface;
        /* store and configure gfx context */
    }
}