diff --git a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c index 7c57bc5c58..75c9f1c353 100644 --- a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c +++ b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c @@ -89,7 +89,7 @@ void guac_rdpsnd_formats_handler(guac_rdp_common_svc* svc, /* Version and padding */ Stream_Write_UINT8(output_stream, 0); - Stream_Write_UINT16(output_stream, 6); + Stream_Write_UINT16(output_stream, 8); Stream_Write_UINT8(output_stream, 0); /* Check each server format, respond if supported and audio is enabled */ @@ -360,6 +360,74 @@ void guac_rdpsnd_wave_handler(guac_rdp_common_svc* svc, } +void guac_rdpsnd_wave2_handler(guac_rdp_common_svc* svc, + wStream* input_stream, guac_rdpsnd_pdu_header* header) { + + int format; + int block_number; + + guac_client* client = svc->client; + guac_rdpsnd* rdpsnd = (guac_rdpsnd*) svc->data; + + guac_rdp_client* rdp_client = (guac_rdp_client*) client->data; + guac_audio_stream* audio = rdp_client->audio; + + int wave_size; + wStream* output_stream; + + /* Wave2 body must include 12-byte header before payload. */ + if (Stream_GetRemainingLength(input_stream) < 12) { + guac_client_log(client, GUAC_LOG_WARNING, "Audio Wave2 PDU does not " + "contain the expected number of bytes. Sound may not work as " + "expected."); + return; + } + + Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp); + Stream_Read_UINT16(input_stream, format); + Stream_Read_UINT8(input_stream, block_number); + Stream_Seek(input_stream, 3); /* bPad */ + Stream_Seek(input_stream, 4); /* dwAudioTimeStamp */ + + wave_size = header->body_size - 12; + if (wave_size <= 0 || Stream_GetRemainingLength(input_stream) < (size_t) wave_size) { + guac_client_log(client, GUAC_LOG_WARNING, "Audio Wave2 PDU contains " + "invalid payload length. Sound may not work as expected."); + return; + } + + if (audio != NULL) { + + if (format < GUAC_RDP_MAX_FORMATS) + guac_audio_stream_reset(audio, NULL, + rdpsnd->formats[format].rate, + rdpsnd->formats[format].channels, + rdpsnd->formats[format].bps); + + else { + guac_client_log(client, GUAC_LOG_WARNING, "RDP server attempted " + "to specify an invalid Wave2 audio format. Sound may not " + "work as expected."); + return; + } + + guac_audio_stream_write_pcm(audio, Stream_Pointer(input_stream), wave_size); + guac_audio_stream_flush(audio); + + } + + output_stream = Stream_New(NULL, 8); + Stream_Write_UINT8(output_stream, SNDC_WAVECONFIRM); + Stream_Write_UINT8(output_stream, 0); + Stream_Write_UINT16(output_stream, 4); + Stream_Write_UINT16(output_stream, rdpsnd->server_timestamp); + Stream_Write_UINT8(output_stream, block_number); + Stream_Write_UINT8(output_stream, 0); + + guac_rdp_common_svc_write(svc, output_stream); + +} + void guac_rdpsnd_close_handler(guac_rdp_common_svc* svc, wStream* input_stream, guac_rdpsnd_pdu_header* header) { diff --git a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.h b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.h index 9271151f99..e03812b858 100644 --- a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.h +++ b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.h @@ -123,6 +123,23 @@ void guac_rdpsnd_wave_info_handler(guac_rdp_common_svc* svc, void guac_rdpsnd_wave_handler(guac_rdp_common_svc* svc, wStream* input_stream, guac_rdpsnd_pdu_header* header); +/** + * Handler for the SNDC_WAVE2 PDU. Unlike SNDC_WAVE/SNDWAV, SNDC_WAVE2 carries + * both wave metadata and audio payload within a single message body. + * + * @param svc + * The RDPSND channel receiving the SNDC_WAVE2 PDU. + * + * @param input_stream + * The FreeRDP input stream containing the remaining raw bytes (after the + * common header) of the SNDC_WAVE2 PDU. + * + * @param header + * The header content of the SNDC_WAVE2 PDU. + */ +void guac_rdpsnd_wave2_handler(guac_rdp_common_svc* svc, + wStream* input_stream, guac_rdpsnd_pdu_header* header); + /** * Handler for the SNDC_CLOSE (Close) PDU. This PDU is sent when audio * streaming has stopped. This PDU is currently ignored by Guacamole. See: @@ -144,4 +161,3 @@ void guac_rdpsnd_close_handler(guac_rdp_common_svc* svc, wStream* input_stream, guac_rdpsnd_pdu_header* header); #endif - diff --git a/src/protocols/rdp/channels/rdpsnd/rdpsnd.c b/src/protocols/rdp/channels/rdpsnd/rdpsnd.c index bbbe6b5ef1..a8acd4e680 100644 --- a/src/protocols/rdp/channels/rdpsnd/rdpsnd.c +++ b/src/protocols/rdp/channels/rdpsnd/rdpsnd.c @@ -76,6 +76,11 @@ void guac_rdpsnd_process_receive(guac_rdp_common_svc* svc, guac_rdpsnd_wave_info_handler(svc, input_stream, &header); break; + /* Wave2 PDU */ + case SNDC_WAVE2: + guac_rdpsnd_wave2_handler(svc, input_stream, &header); + break; + /* Close PDU */ case SNDC_CLOSE: guac_rdpsnd_close_handler(svc, input_stream, &header); @@ -110,4 +115,3 @@ void guac_rdpsnd_load_plugin(rdpContext* context) { } } -