Merge pull request #96 from glyptodon/load-rdpsnd-with-rdpdr
GUAC-1196: Always load RDPSND with RDPDR.
This commit is contained in:
commit
b473ce4f95
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -291,17 +291,8 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
GUAC_RDP_AUDIO_CHANNELS,
|
GUAC_RDP_AUDIO_CHANNELS,
|
||||||
GUAC_RDP_AUDIO_BPS);
|
GUAC_RDP_AUDIO_BPS);
|
||||||
|
|
||||||
/* If an encoding is available, load the sound plugin */
|
/* Warn if no audio encoding is available */
|
||||||
if (guac_client_data->audio != NULL) {
|
if (guac_client_data->audio == NULL)
|
||||||
|
|
||||||
/* Load sound plugin */
|
|
||||||
if (freerdp_channels_load_plugin(channels, instance->settings,
|
|
||||||
"guacsnd", guac_client_data->audio))
|
|
||||||
guac_client_log(client, GUAC_LOG_WARNING,
|
|
||||||
"Failed to load guacsnd plugin. Audio will not work.");
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
guac_client_log(client, GUAC_LOG_INFO,
|
guac_client_log(client, GUAC_LOG_INFO,
|
||||||
"No available audio encoding. Sound disabled.");
|
"No available audio encoding. Sound disabled.");
|
||||||
|
|
||||||
@ -321,7 +312,7 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If RDPDR required, load it */
|
/* If RDPSND/RDPDR required, load them */
|
||||||
if (guac_client_data->settings.printing_enabled
|
if (guac_client_data->settings.printing_enabled
|
||||||
|| guac_client_data->settings.drive_enabled
|
|| guac_client_data->settings.drive_enabled
|
||||||
|| guac_client_data->settings.audio_enabled) {
|
|| guac_client_data->settings.audio_enabled) {
|
||||||
@ -330,7 +321,16 @@ BOOL rdp_freerdp_pre_connect(freerdp* instance) {
|
|||||||
if (freerdp_channels_load_plugin(channels, instance->settings,
|
if (freerdp_channels_load_plugin(channels, instance->settings,
|
||||||
"guacdr", client))
|
"guacdr", client))
|
||||||
guac_client_log(client, GUAC_LOG_WARNING,
|
guac_client_log(client, GUAC_LOG_WARNING,
|
||||||
"Failed to load guacdr plugin. Drive redirection and printing will not work.");
|
"Failed to load guacdr plugin. Drive redirection and "
|
||||||
|
"printing will not work. Sound MAY not work.");
|
||||||
|
|
||||||
|
/* Load RDPSND plugin */
|
||||||
|
if (freerdp_channels_load_plugin(channels, instance->settings,
|
||||||
|
"guacsnd", client))
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING,
|
||||||
|
"Failed to load guacsnd alongside guacdr plugin. Sound "
|
||||||
|
"will not work. Drive redirection and printing MAY not "
|
||||||
|
"work.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -44,8 +44,7 @@
|
|||||||
/* MESSAGE HANDLERS */
|
/* MESSAGE HANDLERS */
|
||||||
|
|
||||||
void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
guac_rdpsnd_pdu_header* header) {
|
|
||||||
|
|
||||||
int server_format_count;
|
int server_format_count;
|
||||||
int server_version;
|
int server_version;
|
||||||
@ -55,8 +54,12 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
int output_body_size;
|
int output_body_size;
|
||||||
unsigned char* output_stream_end;
|
unsigned char* output_stream_end;
|
||||||
|
|
||||||
rdp_guac_client_data* guac_client_data =
|
/* Get associated client data */
|
||||||
(rdp_guac_client_data*) audio->client->data;
|
guac_client* client = rdpsnd->client;
|
||||||
|
rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data;
|
||||||
|
|
||||||
|
/* Get audio stream from client data */
|
||||||
|
guac_audio_stream* audio = client_data->audio;
|
||||||
|
|
||||||
/* Format header */
|
/* Format header */
|
||||||
Stream_Seek(input_stream, 14);
|
Stream_Seek(input_stream, 14);
|
||||||
@ -89,75 +92,86 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
Stream_Write_UINT16(output_stream, 6);
|
Stream_Write_UINT16(output_stream, 6);
|
||||||
Stream_Write_UINT8(output_stream, 0);
|
Stream_Write_UINT8(output_stream, 0);
|
||||||
|
|
||||||
/* Check each server format, respond if supported */
|
/* Check each server format, respond if supported and audio is enabled */
|
||||||
for (i=0; i < server_format_count; i++) {
|
if (audio != NULL) {
|
||||||
|
for (i=0; i < server_format_count; i++) {
|
||||||
|
|
||||||
unsigned char* format_start;
|
unsigned char* format_start;
|
||||||
|
|
||||||
int format_tag;
|
int format_tag;
|
||||||
int channels;
|
int channels;
|
||||||
int rate;
|
int rate;
|
||||||
int bps;
|
int bps;
|
||||||
int body_size;
|
int body_size;
|
||||||
|
|
||||||
/* Remember position in stream */
|
/* Remember position in stream */
|
||||||
Stream_GetPointer(input_stream, format_start);
|
Stream_GetPointer(input_stream, format_start);
|
||||||
|
|
||||||
/* Read format */
|
/* Read format */
|
||||||
Stream_Read_UINT16(input_stream, format_tag);
|
Stream_Read_UINT16(input_stream, format_tag);
|
||||||
Stream_Read_UINT16(input_stream, channels);
|
Stream_Read_UINT16(input_stream, channels);
|
||||||
Stream_Read_UINT32(input_stream, rate);
|
Stream_Read_UINT32(input_stream, rate);
|
||||||
Stream_Seek_UINT32(input_stream);
|
Stream_Seek_UINT32(input_stream);
|
||||||
Stream_Seek_UINT16(input_stream);
|
Stream_Seek_UINT16(input_stream);
|
||||||
Stream_Read_UINT16(input_stream, bps);
|
Stream_Read_UINT16(input_stream, bps);
|
||||||
|
|
||||||
/* Skip past extra data */
|
/* Skip past extra data */
|
||||||
Stream_Read_UINT16(input_stream, body_size);
|
Stream_Read_UINT16(input_stream, body_size);
|
||||||
Stream_Seek(input_stream, body_size);
|
Stream_Seek(input_stream, body_size);
|
||||||
|
|
||||||
/* If PCM, accept */
|
/* If PCM, accept */
|
||||||
if (format_tag == WAVE_FORMAT_PCM) {
|
if (format_tag == WAVE_FORMAT_PCM) {
|
||||||
|
|
||||||
/* If can fit another format, accept it */
|
/* If can fit another format, accept it */
|
||||||
if (rdpsnd->format_count < GUAC_RDP_MAX_FORMATS) {
|
if (rdpsnd->format_count < GUAC_RDP_MAX_FORMATS) {
|
||||||
|
|
||||||
/* Add channel */
|
/* Add channel */
|
||||||
int current = rdpsnd->format_count++;
|
int current = rdpsnd->format_count++;
|
||||||
rdpsnd->formats[current].rate = rate;
|
rdpsnd->formats[current].rate = rate;
|
||||||
rdpsnd->formats[current].channels = channels;
|
rdpsnd->formats[current].channels = channels;
|
||||||
rdpsnd->formats[current].bps = bps;
|
rdpsnd->formats[current].bps = bps;
|
||||||
|
|
||||||
/* Log format */
|
/* Log format */
|
||||||
guac_client_log(audio->client, GUAC_LOG_INFO,
|
guac_client_log(client, GUAC_LOG_INFO,
|
||||||
"Accepted format: %i-bit PCM with %i channels at "
|
"Accepted format: %i-bit PCM with %i channels at "
|
||||||
"%i Hz",
|
"%i Hz",
|
||||||
bps, channels, rate);
|
bps, channels, rate);
|
||||||
|
|
||||||
/* Ensure audio stream is configured to use accepted format */
|
/* Ensure audio stream is configured to use accepted
|
||||||
guac_audio_stream_reset(audio, NULL, rate, channels, bps);
|
* format */
|
||||||
|
guac_audio_stream_reset(audio, NULL, rate, channels, bps);
|
||||||
|
|
||||||
/* Queue format for sending as accepted */
|
/* Queue format for sending as accepted */
|
||||||
Stream_EnsureRemainingCapacity(output_stream, 18 + body_size);
|
Stream_EnsureRemainingCapacity(output_stream,
|
||||||
Stream_Write(output_stream, format_start, 18 + body_size);
|
18 + body_size);
|
||||||
|
Stream_Write(output_stream, format_start, 18 + body_size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BEWARE that using Stream_EnsureRemainingCapacity means that any
|
* BEWARE that using Stream_EnsureRemainingCapacity means
|
||||||
* pointers returned via Stream_GetPointer on output_stream are invalid.
|
* that any pointers returned via Stream_GetPointer on
|
||||||
*/
|
* output_stream are invalid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, log that we dropped one */
|
||||||
|
else
|
||||||
|
guac_client_log(client, GUAC_LOG_INFO,
|
||||||
|
"Dropped valid format: %i-bit PCM with %i "
|
||||||
|
"channels at %i Hz",
|
||||||
|
bps, channels, rate);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, log that we dropped one */
|
|
||||||
else
|
|
||||||
guac_client_log(audio->client, GUAC_LOG_INFO,
|
|
||||||
"Dropped valid format: %i-bit PCM with %i channels at "
|
|
||||||
"%i Hz",
|
|
||||||
bps, channels, rate);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Otherwise, ignore all supported formats as we do not intend to actually
|
||||||
|
* receive audio */
|
||||||
|
else
|
||||||
|
guac_client_log(client, GUAC_LOG_DEBUG,
|
||||||
|
"Audio explicitly disabled. Ignoring supported formats.");
|
||||||
|
|
||||||
/* Calculate size of PDU */
|
/* Calculate size of PDU */
|
||||||
output_body_size = Stream_GetPosition(output_stream) - 4;
|
output_body_size = Stream_GetPosition(output_stream) - 4;
|
||||||
Stream_GetPointer(output_stream, output_stream_end);
|
Stream_GetPointer(output_stream, output_stream_end);
|
||||||
@ -174,7 +188,7 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
Stream_SetPointer(output_stream, output_stream_end);
|
Stream_SetPointer(output_stream, output_stream_end);
|
||||||
|
|
||||||
/* Send accepted formats */
|
/* Send accepted formats */
|
||||||
pthread_mutex_lock(&(guac_client_data->rdp_lock));
|
pthread_mutex_lock(&(client_data->rdp_lock));
|
||||||
svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream);
|
svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream);
|
||||||
|
|
||||||
/* If version greater than 6, must send Quality Mode PDU */
|
/* If version greater than 6, must send Quality Mode PDU */
|
||||||
@ -191,20 +205,20 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream);
|
svc_plugin_send((rdpSvcPlugin*)rdpsnd, output_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
|
pthread_mutex_unlock(&(client_data->rdp_lock));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* server is getting a feel of the round trip time */
|
/* server is getting a feel of the round trip time */
|
||||||
void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
guac_rdpsnd_pdu_header* header) {
|
|
||||||
|
|
||||||
int data_size;
|
int data_size;
|
||||||
wStream* output_stream;
|
wStream* output_stream;
|
||||||
|
|
||||||
rdp_guac_client_data* guac_client_data =
|
/* Get associated client data */
|
||||||
(rdp_guac_client_data*) audio->client->data;
|
guac_client* client = rdpsnd->client;
|
||||||
|
rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data;
|
||||||
|
|
||||||
/* Read timestamp and data size */
|
/* Read timestamp and data size */
|
||||||
Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
|
Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
|
||||||
@ -218,18 +232,24 @@ void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
Stream_Write_UINT16(output_stream, rdpsnd->server_timestamp);
|
Stream_Write_UINT16(output_stream, rdpsnd->server_timestamp);
|
||||||
Stream_Write_UINT16(output_stream, data_size);
|
Stream_Write_UINT16(output_stream, data_size);
|
||||||
|
|
||||||
pthread_mutex_lock(&(guac_client_data->rdp_lock));
|
pthread_mutex_lock(&(client_data->rdp_lock));
|
||||||
svc_plugin_send((rdpSvcPlugin*) rdpsnd, output_stream);
|
svc_plugin_send((rdpSvcPlugin*) rdpsnd, output_stream);
|
||||||
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
|
pthread_mutex_unlock(&(client_data->rdp_lock));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
guac_rdpsnd_pdu_header* header) {
|
|
||||||
|
|
||||||
int format;
|
int format;
|
||||||
|
|
||||||
|
/* Get associated client data */
|
||||||
|
guac_client* client = rdpsnd->client;
|
||||||
|
rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data;
|
||||||
|
|
||||||
|
/* Get audio stream from client data */
|
||||||
|
guac_audio_stream* audio = client_data->audio;
|
||||||
|
|
||||||
/* Read wave information */
|
/* Read wave information */
|
||||||
Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
|
Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
|
||||||
Stream_Read_UINT16(input_stream, format);
|
Stream_Read_UINT16(input_stream, format);
|
||||||
@ -248,21 +268,25 @@ void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
rdpsnd->next_pdu_is_wave = TRUE;
|
rdpsnd->next_pdu_is_wave = TRUE;
|
||||||
|
|
||||||
/* Reset audio stream if format has changed */
|
/* Reset audio stream if format has changed */
|
||||||
guac_audio_stream_reset(audio, NULL,
|
if (audio != NULL)
|
||||||
rdpsnd->formats[format].rate,
|
guac_audio_stream_reset(audio, NULL,
|
||||||
rdpsnd->formats[format].channels,
|
rdpsnd->formats[format].rate,
|
||||||
rdpsnd->formats[format].bps);
|
rdpsnd->formats[format].channels,
|
||||||
|
rdpsnd->formats[format].bps);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
guac_rdpsnd_pdu_header* header) {
|
|
||||||
|
|
||||||
rdpSvcPlugin* plugin = (rdpSvcPlugin*)rdpsnd;
|
rdpSvcPlugin* plugin = (rdpSvcPlugin*)rdpsnd;
|
||||||
|
|
||||||
rdp_guac_client_data* guac_client_data =
|
/* Get associated client data */
|
||||||
(rdp_guac_client_data*) audio->client->data;
|
guac_client* client = rdpsnd->client;
|
||||||
|
rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data;
|
||||||
|
|
||||||
|
/* Get audio stream from client data */
|
||||||
|
guac_audio_stream* audio = client_data->audio;
|
||||||
|
|
||||||
/* Wave Confirmation PDU */
|
/* Wave Confirmation PDU */
|
||||||
wStream* output_stream = Stream_New(NULL, 8);
|
wStream* output_stream = Stream_New(NULL, 8);
|
||||||
@ -274,8 +298,11 @@ void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
memcpy(buffer, rdpsnd->initial_wave_data, 4);
|
memcpy(buffer, rdpsnd->initial_wave_data, 4);
|
||||||
|
|
||||||
/* Write rest of audio packet */
|
/* Write rest of audio packet */
|
||||||
guac_audio_stream_write_pcm(audio, buffer, rdpsnd->incoming_wave_size + 4);
|
if (audio != NULL) {
|
||||||
guac_audio_stream_flush(audio);
|
guac_audio_stream_write_pcm(audio, buffer,
|
||||||
|
rdpsnd->incoming_wave_size + 4);
|
||||||
|
guac_audio_stream_flush(audio);
|
||||||
|
}
|
||||||
|
|
||||||
/* Write Wave Confirmation PDU */
|
/* Write Wave Confirmation PDU */
|
||||||
Stream_Write_UINT8(output_stream, SNDC_WAVECONFIRM);
|
Stream_Write_UINT8(output_stream, SNDC_WAVECONFIRM);
|
||||||
@ -286,9 +313,9 @@ void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
Stream_Write_UINT8(output_stream, 0);
|
Stream_Write_UINT8(output_stream, 0);
|
||||||
|
|
||||||
/* Send Wave Confirmation PDU */
|
/* Send Wave Confirmation PDU */
|
||||||
pthread_mutex_lock(&(guac_client_data->rdp_lock));
|
pthread_mutex_lock(&(client_data->rdp_lock));
|
||||||
svc_plugin_send(plugin, output_stream);
|
svc_plugin_send(plugin, output_stream);
|
||||||
pthread_mutex_unlock(&(guac_client_data->rdp_lock));
|
pthread_mutex_unlock(&(client_data->rdp_lock));
|
||||||
|
|
||||||
/* We no longer expect to receive wave data */
|
/* We no longer expect to receive wave data */
|
||||||
rdpsnd->next_pdu_is_wave = FALSE;
|
rdpsnd->next_pdu_is_wave = FALSE;
|
||||||
@ -296,10 +323,9 @@ void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void guac_rdpsnd_close_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_close_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header) {
|
||||||
guac_rdpsnd_pdu_header* header) {
|
|
||||||
|
|
||||||
/* STUB: Do nothing for now */
|
/* Do nothing */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -28,8 +28,6 @@
|
|||||||
|
|
||||||
#include "rdpsnd_service.h"
|
#include "rdpsnd_service.h"
|
||||||
|
|
||||||
#include <guacamole/audio.h>
|
|
||||||
|
|
||||||
#ifdef ENABLE_WINPR
|
#ifdef ENABLE_WINPR
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
#else
|
#else
|
||||||
@ -122,39 +120,106 @@ typedef struct guac_rdpsnd_pdu_header {
|
|||||||
} guac_rdpsnd_pdu_header;
|
} guac_rdpsnd_pdu_header;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the SNDC_FORMATS (Server Audio Formats and Version) PDU.
|
* Handler for the SNDC_FORMATS (Server Audio Formats and Version) PDU. The
|
||||||
|
* SNDC_FORMATS PDU describes all audio formats supported by the RDP server, as
|
||||||
|
* well as the version of RDPSND implemented.
|
||||||
|
*
|
||||||
|
* @param rdpsnd
|
||||||
|
* The Guacamole RDPSND plugin receiving the SNDC_FORMATS PDU.
|
||||||
|
*
|
||||||
|
* @param input_stream
|
||||||
|
* The FreeRDP input stream containing the remaining raw bytes (after the
|
||||||
|
* common header) of the SNDC_FORMATS PDU.
|
||||||
|
*
|
||||||
|
* @param header
|
||||||
|
* The header content of the SNDC_FORMATS PDU. All RDPSND messages contain
|
||||||
|
* the same header information.
|
||||||
*/
|
*/
|
||||||
void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header);
|
||||||
guac_rdpsnd_pdu_header* header);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the SNDC_TRAINING (Training) PDU.
|
* Handler for the SNDC_TRAINING (Training) PDU. The SNDC_TRAINING PDU is used
|
||||||
|
* to by RDP servers to test audio streaming latency, etc. without actually
|
||||||
|
* sending audio data. See:
|
||||||
|
*
|
||||||
|
* https://msdn.microsoft.com/en-us/library/cc240961.aspx
|
||||||
|
*
|
||||||
|
* @param rdpsnd
|
||||||
|
* The Guacamole RDPSND plugin receiving the SNDC_TRAINING PDU.
|
||||||
|
*
|
||||||
|
* @param input_stream
|
||||||
|
* The FreeRDP input stream containing the remaining raw bytes (after the
|
||||||
|
* common header) of the SNDC_TRAINING PDU.
|
||||||
|
*
|
||||||
|
* @param header
|
||||||
|
* The header content of the SNDC_TRAINING PDU. All RDPSND messages contain
|
||||||
|
* the same header information.
|
||||||
*/
|
*/
|
||||||
void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header);
|
||||||
guac_rdpsnd_pdu_header* header);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the SNDC_WAVE (WaveInfo) PDU.
|
* Handler for the SNDC_WAVE (WaveInfo) PDU. The SNDC_WAVE immediately precedes
|
||||||
|
* a SNDWAV PDU and describes the data about to be received. It also (very
|
||||||
|
* strangely) contains exactly 4 bytes of audio data. The following SNDWAV PDU
|
||||||
|
* then contains 4 bytes of padding prior to the audio data where it would make
|
||||||
|
* perfect sense for this data to go. See:
|
||||||
|
*
|
||||||
|
* https://msdn.microsoft.com/en-us/library/cc240963.aspx
|
||||||
|
*
|
||||||
|
* @param rdpsnd
|
||||||
|
* The Guacamole RDPSND plugin receiving the SNDC_WAVE PDU.
|
||||||
|
*
|
||||||
|
* @param input_stream
|
||||||
|
* The FreeRDP input stream containing the remaining raw bytes (after the
|
||||||
|
* common header) of the SNDC_WAVE PDU.
|
||||||
|
*
|
||||||
|
* @param header
|
||||||
|
* The header content of the SNDC_WAVE PDU. All RDPSND messages contain
|
||||||
|
* the same header information.
|
||||||
*/
|
*/
|
||||||
void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header);
|
||||||
guac_rdpsnd_pdu_header* header);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the SNDWAV (Wave) PDU which follows any WaveInfo PDU.
|
* Handler for the SNDWAV (Wave) PDU which follows any WaveInfo PDU. The SNDWAV
|
||||||
|
* PDU contains the actual audio data, less the four bytes of audio data
|
||||||
|
* included in the SNDC_WAVE PDU.
|
||||||
|
*
|
||||||
|
* @param rdpsnd
|
||||||
|
* The Guacamole RDPSND plugin receiving the SNDWAV PDU.
|
||||||
|
*
|
||||||
|
* @param input_stream
|
||||||
|
* The FreeRDP input stream containing the remaining raw bytes (after the
|
||||||
|
* common header) of the SNDWAV PDU.
|
||||||
|
*
|
||||||
|
* @param header
|
||||||
|
* The header content of the SNDWAV PDU. All RDPSND messages contain
|
||||||
|
* the same header information.
|
||||||
*/
|
*/
|
||||||
void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header);
|
||||||
guac_rdpsnd_pdu_header* header);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for the SNDC_CLOSE (Close) PDU.
|
* Handler for the SNDC_CLOSE (Close) PDU. This PDU is sent when audio
|
||||||
|
* streaming has stopped. This PDU is currently ignored by Guacamole. See:
|
||||||
|
*
|
||||||
|
* https://msdn.microsoft.com/en-us/library/cc240970.aspx
|
||||||
|
*
|
||||||
|
* @param rdpsnd
|
||||||
|
* The Guacamole RDPSND plugin receiving the SNDC_CLOSE PDU.
|
||||||
|
*
|
||||||
|
* @param input_stream
|
||||||
|
* The FreeRDP input stream containing the remaining raw bytes (after the
|
||||||
|
* common header) of the SNDC_CLOSE PDU.
|
||||||
|
*
|
||||||
|
* @param header
|
||||||
|
* The header content of the SNDC_CLOSE PDU. All RDPSND messages contain
|
||||||
|
* the same header information.
|
||||||
*/
|
*/
|
||||||
void guac_rdpsnd_close_handler(guac_rdpsndPlugin* rdpsnd,
|
void guac_rdpsnd_close_handler(guac_rdpsndPlugin* rdpsnd,
|
||||||
guac_audio_stream* audio, wStream* input_stream,
|
wStream* input_stream, guac_rdpsnd_pdu_header* header);
|
||||||
guac_rdpsnd_pdu_header* header);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
#include <freerdp/constants.h>
|
#include <freerdp/constants.h>
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
#include <freerdp/utils/svc_plugin.h>
|
||||||
#include <guacamole/audio.h>
|
|
||||||
#include <guacamole/client.h>
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
#ifdef ENABLE_WINPR
|
#ifdef ENABLE_WINPR
|
||||||
@ -73,11 +72,11 @@ void guac_rdpsnd_process_connect(rdpSvcPlugin* plugin) {
|
|||||||
|
|
||||||
guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin;
|
guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin;
|
||||||
|
|
||||||
/* Get audio stream from plugin parameters */
|
/* Get client from plugin parameters */
|
||||||
guac_audio_stream* audio = rdpsnd->audio =
|
guac_client* client = rdpsnd->client =
|
||||||
(guac_audio_stream*) plugin->channel_entry_points.pExtendedData;
|
(guac_client*) plugin->channel_entry_points.pExtendedData;
|
||||||
|
|
||||||
/* NULL out pExtendedData so we don't lose our guac_audio_stream due to an
|
/* NULL out pExtendedData so we don't lose our guac_client due to an
|
||||||
* automatic free() within libfreerdp */
|
* automatic free() within libfreerdp */
|
||||||
plugin->channel_entry_points.pExtendedData = NULL;
|
plugin->channel_entry_points.pExtendedData = NULL;
|
||||||
|
|
||||||
@ -87,7 +86,7 @@ void guac_rdpsnd_process_connect(rdpSvcPlugin* plugin) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Log that sound has been loaded */
|
/* Log that sound has been loaded */
|
||||||
guac_client_log(audio->client, GUAC_LOG_INFO, "guacsnd connected.");
|
guac_client_log(client, GUAC_LOG_INFO, "guacsnd connected.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,9 +104,6 @@ void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin,
|
|||||||
guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin;
|
guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin;
|
||||||
guac_rdpsnd_pdu_header header;
|
guac_rdpsnd_pdu_header header;
|
||||||
|
|
||||||
/* Get audio stream from plugin */
|
|
||||||
guac_audio_stream* audio = rdpsnd->audio;
|
|
||||||
|
|
||||||
/* Read RDPSND PDU header */
|
/* Read RDPSND PDU header */
|
||||||
Stream_Read_UINT8(input_stream, header.message_type);
|
Stream_Read_UINT8(input_stream, header.message_type);
|
||||||
Stream_Seek_UINT8(input_stream);
|
Stream_Seek_UINT8(input_stream);
|
||||||
@ -118,7 +114,7 @@ void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin,
|
|||||||
* ignore the header and parse as a Wave PDU.
|
* ignore the header and parse as a Wave PDU.
|
||||||
*/
|
*/
|
||||||
if (rdpsnd->next_pdu_is_wave) {
|
if (rdpsnd->next_pdu_is_wave) {
|
||||||
guac_rdpsnd_wave_handler(rdpsnd, audio, input_stream, &header);
|
guac_rdpsnd_wave_handler(rdpsnd, input_stream, &header);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,26 +123,22 @@ void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin,
|
|||||||
|
|
||||||
/* Server Audio Formats and Version PDU */
|
/* Server Audio Formats and Version PDU */
|
||||||
case SNDC_FORMATS:
|
case SNDC_FORMATS:
|
||||||
guac_rdpsnd_formats_handler(rdpsnd, audio,
|
guac_rdpsnd_formats_handler(rdpsnd, input_stream, &header);
|
||||||
input_stream, &header);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Training PDU */
|
/* Training PDU */
|
||||||
case SNDC_TRAINING:
|
case SNDC_TRAINING:
|
||||||
guac_rdpsnd_training_handler(rdpsnd, audio,
|
guac_rdpsnd_training_handler(rdpsnd, input_stream, &header);
|
||||||
input_stream, &header);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* WaveInfo PDU */
|
/* WaveInfo PDU */
|
||||||
case SNDC_WAVE:
|
case SNDC_WAVE:
|
||||||
guac_rdpsnd_wave_info_handler(rdpsnd, audio,
|
guac_rdpsnd_wave_info_handler(rdpsnd, input_stream, &header);
|
||||||
input_stream, &header);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Close PDU */
|
/* Close PDU */
|
||||||
case SNDC_CLOSE:
|
case SNDC_CLOSE:
|
||||||
guac_rdpsnd_close_handler(rdpsnd, audio,
|
guac_rdpsnd_close_handler(rdpsnd, input_stream, &header);
|
||||||
input_stream, &header);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Glyptodon LLC
|
* Copyright (C) 2015 Glyptodon LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -27,7 +27,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <freerdp/utils/svc_plugin.h>
|
#include <freerdp/utils/svc_plugin.h>
|
||||||
#include <guacamole/audio.h>
|
#include <guacamole/client.h>
|
||||||
|
|
||||||
#ifdef ENABLE_WINPR
|
#ifdef ENABLE_WINPR
|
||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
@ -80,9 +80,10 @@ typedef struct guac_rdpsndPlugin {
|
|||||||
rdpSvcPlugin plugin;
|
rdpSvcPlugin plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current audio stream.
|
* The Guacamole client associated with the guac_audio_stream that this
|
||||||
|
* plugin should use to stream received audio packets.
|
||||||
*/
|
*/
|
||||||
guac_audio_stream* audio;
|
guac_client* client;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The block number of the last SNDC_WAVE (WaveInfo) PDU received.
|
* The block number of the last SNDC_WAVE (WaveInfo) PDU received.
|
||||||
|
Loading…
Reference in New Issue
Block a user