Skip to main content
The RDPSND channel implements [MS-RDPEA] — Remote Desktop Protocol: Audio Output Virtual Channel Extension. It streams audio from the server to the client. SVC channel name: rdpsnd (RDPSND_CHANNEL_NAME)
DVC channel names: AUDIO_PLAYBACK_DVC, AUDIO_PLAYBACK_LOSSY_DVC
Server header: <freerdp/server/rdpsnd.h>
Client header: <freerdp/client/rdpsnd.h>
Common types: <freerdp/channels/rdpsnd.h> (re-exports <freerdp/codec/audio.h>)

Server API

RdpsndServerContext lifecycle

RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm);
void                 rdpsnd_server_context_free(RdpsndServerContext* context);
void                 rdpsnd_server_context_reset(RdpsndServerContext* context);
vcm is the virtual channel manager handle. reset reinitialises the context without freeing, for reuse after a session reconnect.

Helper functions

HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context);
UINT   rdpsnd_server_handle_messages(RdpsndServerContext* context);
Use rdpsnd_server_get_event_handle() in a wait-loop and call rdpsnd_server_handle_messages() when signalled to process incoming client PDUs.

RdpsndServerContext fields

data
void*
Server-defined private pointer.
use_dynamic_virtual_channel
BOOL
Set to TRUE before Initialize to open via DVC (AUDIO_PLAYBACK_DVC) instead of the legacy SVC.
server_formats
AUDIO_FORMAT*
Array of AUDIO_FORMAT structs the server supports. Set before calling Initialize.
num_server_formats
size_t
Length of server_formats.
src_format
AUDIO_FORMAT*
The PCM format of the audio source (sample rate, channels, bits-per-sample). Set before SendSamples.
latency
UINT32
Requested audio buffer / latency in milliseconds.
client_formats
AUDIO_FORMAT*
Populated by the channel after format negotiation with the client. Read-only for the server.
num_client_formats
UINT16
Number of entries in client_formats.
selected_client_format
UINT16
Index into client_formats of the currently active format. Set by SelectFormat.

Server API calls

Initialize
psRdpsndServerInitialize
typedef UINT (*psRdpsndServerInitialize)(RdpsndServerContext* context, BOOL ownThread);
Opens the channel and begins format negotiation. If ownThread = TRUE the implementation spawns a worker thread; otherwise the caller must drive messages via rdpsnd_server_handle_messages().
SelectFormat
psRdpsndServerSelectFormat
typedef UINT (*psRdpsndServerSelectFormat)(RdpsndServerContext* context,
                                          UINT16 client_format_index);
Selects the client audio format at client_format_index (index into client_formats). Must be called before SendSamples.
SendFormats
psRdpsndServerSendFormats
typedef UINT (*psRdpsndServerSendFormats)(RdpsndServerContext* context);
Re-sends the server format list and version PDU. Normally called automatically by Initialize; call manually to restart the protocol after Close.
SendSamples
psRdpsndServerSendSamples
typedef UINT (*psRdpsndServerSendSamples)(RdpsndServerContext* context,
                                         const void* buf, size_t nframes,
                                         UINT16 wTimestamp);
Sends PCM audio data in src_format. nframes is the number of audio frames (not bytes). The channel converts to the negotiated client format internally if a DSP is configured.
SendSamples2
psRdpsndServerSendSamples2
typedef UINT (*psRdpsndServerSendSamples2)(RdpsndServerContext* context,
                                          UINT16 formatNo, const void* buf,
                                          size_t size, UINT16 timestamp,
                                          UINT32 audioTimeStamp);
Sends already-encoded audio via a Wave2 PDU. formatNo is an index into client_formats. Bypasses any internal DSP conversion.
SetVolume
psRdpsndServerSetVolume
typedef UINT (*psRdpsndServerSetVolume)(RdpsndServerContext* context,
                                       UINT16 left, UINT16 right);
Sets the client-side playback volume. Valid range is 0x0000 (mute) to 0xFFFF (full).
Training
psRdpsndServerTraining
typedef UINT (*psRdpsndServerTraining)(RdpsndServerContext* context,
                                      UINT16 timestamp, UINT16 packsize,
                                      BYTE* data);
Sends a Training PDU used for round-trip time measurement.

Server callbacks

Activated
psRdpsndServerActivated
typedef void (*psRdpsndServerActivated)(RdpsndServerContext* context);
Called (from the worker thread) when the client has completed format negotiation and is ready to receive audio. Start streaming from this callback.
TrainingConfirm
psRdpsndServerTrainingConfirm
typedef UINT (*psRdpsndServerTrainingConfirm)(RdpsndServerContext* context,
                                             UINT16 timestamp, UINT16 packsize);
Called when the client confirms a Training PDU. Use to calculate round-trip latency.
ConfirmBlock
psRdpsndServerConfirmBlock
typedef UINT (*psRdpsndServerConfirmBlock)(RdpsndServerContext* context,
                                          BYTE confirmBlockNum, UINT16 wtimestamp);
Called when the client acknowledges a WaveConfirm PDU. Used for flow control.

Client Device Plugin

The client side uses an rdpsndDevicePlugin (audio output backend — e.g. PulseAudio, ALSA, Windows CoreAudio).
struct rdpsnd_device_plugin {
    rdpsndPlugin*           rdpsnd;
    pcFormatSupported       FormatSupported;   /* BOOL(device, format) */
    pcOpen                  Open;              /* BOOL(device, format, latency) */
    pcGetVolume             GetVolume;         /* UINT32(device) */
    pcSetVolume             SetVolume;         /* BOOL(device, value) */
    pcPlay                  Play;              /* UINT(device, data, size) */
    pcPlayEx                PlayEx;            /* UINT(device, format, data, size) */
    pcClose                 Close;
    pcFree                  Free;
    pcDefaultFormat         DefaultFormat;     /* negotiate preferred format */
    pcServerFormatAnnounce  ServerFormatAnnounce; /* called with server formats */
};
Register a custom backend by implementing freerdp_rdpsnd_client_subsystem_entry (RDPSND_DEVICE_EXPORT_FUNC_NAME) returning a populated rdpsndDevicePlugin.

Audio Codec Support

Always available — built-in codec in WinPR. No extra dependencies.

Minimal Server Usage

#include <freerdp/server/rdpsnd.h>

static void on_rdpsnd_activated(RdpsndServerContext* context)
{
    /* Pick first mutually supported format */
    context->SelectFormat(context, 0);
    /* Feed audio from your source... */
}

RdpsndServerContext* rdpsnd = rdpsnd_server_context_new(vcm);
rdpsnd->data      = my_state;
rdpsnd->Activated = on_rdpsnd_activated;

/* Define PCM source format */
AUDIO_FORMAT fmt = { WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0, NULL };
rdpsnd->src_format = &fmt;

/* Advertise formats */
rdpsnd->server_formats     = my_formats;
rdpsnd->num_server_formats = my_format_count;

rdpsnd->Initialize(rdpsnd, TRUE); /* own thread */