GUACAMOLE-25: Handle the server's Sound Formats PDU.
This commit is contained in:
parent
503ffb0d45
commit
86806a3759
@ -35,6 +35,126 @@
|
|||||||
#include "compat/winpr-stream.h"
|
#include "compat/winpr-stream.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads AUDIO_FORMAT data from the given stream into the given struct.
|
||||||
|
*
|
||||||
|
* @param stream
|
||||||
|
* The stream to read AUDIO_FORMAT data from.
|
||||||
|
*
|
||||||
|
* @param format
|
||||||
|
* The structure to populate with data from the stream.
|
||||||
|
*/
|
||||||
|
static void guac_rdp_ai_read_format(wStream* stream,
|
||||||
|
guac_rdp_ai_format* format) {
|
||||||
|
|
||||||
|
/* Read audio format into structure */
|
||||||
|
Stream_Read_UINT16(stream, format->tag); /* wFormatTag */
|
||||||
|
Stream_Read_UINT16(stream, format->channels); /* nChannels */
|
||||||
|
Stream_Read_UINT32(stream, format->rate); /* nSamplesPerSec */
|
||||||
|
Stream_Read_UINT32(stream, format->bytes_per_sec); /* nAvgBytesPerSec */
|
||||||
|
Stream_Read_UINT16(stream, format->block_align); /* nBlockAlign */
|
||||||
|
Stream_Read_UINT16(stream, format->bps); /* wBitsPerSample */
|
||||||
|
Stream_Read_UINT16(stream, format->data_size); /* cbSize */
|
||||||
|
|
||||||
|
/* Read arbitrary data block (if applicable) */
|
||||||
|
if (format->data_size != 0) {
|
||||||
|
format->data = Stream_Pointer(stream); /* data */
|
||||||
|
Stream_Seek(stream, format->data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes AUDIO_FORMAT data to the given stream from the given struct.
|
||||||
|
*
|
||||||
|
* @param stream
|
||||||
|
* The stream to write AUDIO_FORMAT data to.
|
||||||
|
*
|
||||||
|
* @param format
|
||||||
|
* The structure containing the data that should be written to the stream.
|
||||||
|
*/
|
||||||
|
static void guac_rdp_ai_write_format(wStream* stream,
|
||||||
|
guac_rdp_ai_format* format) {
|
||||||
|
|
||||||
|
/* Write audio format into structure */
|
||||||
|
Stream_Write_UINT16(stream, format->tag); /* wFormatTag */
|
||||||
|
Stream_Write_UINT16(stream, format->channels); /* nChannels */
|
||||||
|
Stream_Write_UINT32(stream, format->rate); /* nSamplesPerSec */
|
||||||
|
Stream_Write_UINT32(stream, format->bytes_per_sec); /* nAvgBytesPerSec */
|
||||||
|
Stream_Write_UINT16(stream, format->block_align); /* nBlockAlign */
|
||||||
|
Stream_Write_UINT16(stream, format->bps); /* wBitsPerSample */
|
||||||
|
Stream_Write_UINT16(stream, format->data_size); /* cbSize */
|
||||||
|
|
||||||
|
/* Write arbitrary data block (if applicable) */
|
||||||
|
if (format->data_size != 0)
|
||||||
|
Stream_Write(stream, format->data, format->data_size);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a Data Incoming PDU along the given channel. A Data Incoming PDU is
|
||||||
|
* used by the client to indicate to the server that format or audio data is
|
||||||
|
* about to be sent.
|
||||||
|
*
|
||||||
|
* @param channel
|
||||||
|
* The channel along which the PDU should be sent.
|
||||||
|
*/
|
||||||
|
static void guac_rdp_ai_send_incoming_data(IWTSVirtualChannel* channel) {
|
||||||
|
|
||||||
|
/* Build response version PDU */
|
||||||
|
wStream* response = Stream_New(NULL, 1);
|
||||||
|
Stream_Write_UINT8(response, GUAC_RDP_MSG_SNDIN_DATA_INCOMING); /* MessageId */
|
||||||
|
|
||||||
|
/* Send response */
|
||||||
|
channel->Write(channel, (UINT32) Stream_GetPosition(response),
|
||||||
|
Stream_Buffer(response), NULL);
|
||||||
|
Stream_Free(response, TRUE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a Sound Formats PDU along the given channel. A Sound Formats PDU is
|
||||||
|
* used by the client to indicate to the server which formats of audio it
|
||||||
|
* supports (in response to the server sending exactly the same type of PDU).
|
||||||
|
* This PDU MUST be preceded by the Data Incoming PDU.
|
||||||
|
*
|
||||||
|
* @param channel
|
||||||
|
* The channel along which the PDU should be sent.
|
||||||
|
*
|
||||||
|
* @param formats
|
||||||
|
* An array of all supported formats.
|
||||||
|
*
|
||||||
|
* @param num_formats
|
||||||
|
* The number of entries in the formats array.
|
||||||
|
*/
|
||||||
|
static void guac_rdp_ai_send_formats(IWTSVirtualChannel* channel,
|
||||||
|
guac_rdp_ai_format* formats, int num_formats) {
|
||||||
|
|
||||||
|
int index;
|
||||||
|
int packet_size = 9;
|
||||||
|
|
||||||
|
/* Calculate packet size */
|
||||||
|
for (index = 0; index < num_formats; index++)
|
||||||
|
packet_size += 18 + formats[index].data_size;
|
||||||
|
|
||||||
|
wStream* stream = Stream_New(NULL, packet_size);
|
||||||
|
|
||||||
|
/* Write header */
|
||||||
|
Stream_Write_UINT8(stream, GUAC_RDP_MSG_SNDIN_FORMATS); /* MessageId */
|
||||||
|
Stream_Write_UINT32(stream, num_formats); /* NumFormats */
|
||||||
|
Stream_Write_UINT32(stream, packet_size); /* cbSizeFormatsPacket */
|
||||||
|
|
||||||
|
/* Write all formats */
|
||||||
|
for (index = 0; index < num_formats; index++)
|
||||||
|
guac_rdp_ai_write_format(stream, &(formats[index]));
|
||||||
|
|
||||||
|
/* Send PDU */
|
||||||
|
channel->Write(channel, (UINT32) Stream_GetPosition(stream),
|
||||||
|
Stream_Buffer(stream), NULL);
|
||||||
|
Stream_Free(stream, TRUE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void guac_rdp_ai_process_version(guac_client* client,
|
void guac_rdp_ai_process_version(guac_client* client,
|
||||||
IWTSVirtualChannel* channel, wStream* stream) {
|
IWTSVirtualChannel* channel, wStream* stream) {
|
||||||
|
|
||||||
@ -61,8 +181,31 @@ void guac_rdp_ai_process_version(guac_client* client,
|
|||||||
void guac_rdp_ai_process_formats(guac_client* client,
|
void guac_rdp_ai_process_formats(guac_client* client,
|
||||||
IWTSVirtualChannel* channel, wStream* stream) {
|
IWTSVirtualChannel* channel, wStream* stream) {
|
||||||
|
|
||||||
/* STUB */
|
UINT32 num_formats;
|
||||||
guac_client_log(client, GUAC_LOG_DEBUG, "AUDIO_INPUT: formats");
|
Stream_Read_UINT32(stream, num_formats); /* NumFormats */
|
||||||
|
Stream_Seek_UINT32(stream); /* cbSizeFormatsPacket (MUST BE IGNORED) */
|
||||||
|
|
||||||
|
UINT32 index;
|
||||||
|
for (index = 0; index < num_formats; index++) {
|
||||||
|
|
||||||
|
guac_rdp_ai_format format;
|
||||||
|
guac_rdp_ai_read_format(stream, &format);
|
||||||
|
|
||||||
|
/* Ignore anything but WAVE_FORMAT_PCM */
|
||||||
|
if (format.tag != GUAC_RDP_WAVE_FORMAT_PCM)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Accept single format */
|
||||||
|
guac_rdp_ai_send_incoming_data(channel);
|
||||||
|
guac_rdp_ai_send_formats(channel, &format, 1);
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No formats available */
|
||||||
|
guac_client_log(client, GUAC_LOG_WARNING, "AUDIO_INPUT: No WAVE format.");
|
||||||
|
guac_rdp_ai_send_incoming_data(channel);
|
||||||
|
guac_rdp_ai_send_formats(channel, NULL, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,12 @@
|
|||||||
#include "compat/winpr-stream.h"
|
#include "compat/winpr-stream.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The format tag associated with raw wave audio (WAVE_FORMAT_PCM). This format
|
||||||
|
* is required to be supported by all RDP servers.
|
||||||
|
*/
|
||||||
|
#define GUAC_RDP_WAVE_FORMAT_PCM 0x01
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message ID associated with the AUDIO_INPUT Version PDU. The Version PDU
|
* The message ID associated with the AUDIO_INPUT Version PDU. The Version PDU
|
||||||
* is sent by both the client and the server to indicate their version of the
|
* is sent by both the client and the server to indicate their version of the
|
||||||
@ -79,6 +85,59 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_RDP_MSG_SNDIN_FORMATCHANGE 0x07
|
#define GUAC_RDP_MSG_SNDIN_FORMATCHANGE 0x07
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An AUDIO_INPUT format, analogous to the AUDIO_FORMAT structure defined
|
||||||
|
* within Microsoft's RDP documentation.
|
||||||
|
*/
|
||||||
|
typedef struct guac_rdp_ai_format {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "format tag" denoting the overall format of audio data received,
|
||||||
|
* such as WAVE_FORMAT_PCM.
|
||||||
|
*/
|
||||||
|
UINT16 tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of audio channels.
|
||||||
|
*/
|
||||||
|
UINT16 channels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of samples per second.
|
||||||
|
*/
|
||||||
|
UINT32 rate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The average number of bytes required for one second of audio.
|
||||||
|
*/
|
||||||
|
UINT32 bytes_per_sec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The absolute minimum number of bytes required to process audio in this
|
||||||
|
* format.
|
||||||
|
*/
|
||||||
|
UINT16 block_align;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of bits per sample.
|
||||||
|
*/
|
||||||
|
UINT16 bps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the arbitrary data block, if any. The meaning of the data
|
||||||
|
* within the arbitrary data block is determined by the format tag.
|
||||||
|
* WAVE_FORMAT_PCM audio has no associated arbitrary data.
|
||||||
|
*/
|
||||||
|
UINT16 data_size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional arbitrary data whose meaning is determined by the format tag.
|
||||||
|
* WAVE_FORMAT_PCM audio has no associated arbitrary data.
|
||||||
|
*/
|
||||||
|
BYTE* data;
|
||||||
|
|
||||||
|
} guac_rdp_ai_format;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a Version PDU received from the RDP server. The Version PDU is
|
* Processes a Version PDU received from the RDP server. The Version PDU is
|
||||||
* sent by the server to indicate its version of the AUDIO_INPUT channel
|
* sent by the server to indicate its version of the AUDIO_INPUT channel
|
||||||
|
Loading…
Reference in New Issue
Block a user