diff --git a/src/protocols/vnc/client.c b/src/protocols/vnc/client.c index ba2717b8..7c6331e2 100644 --- a/src/protocols/vnc/client.c +++ b/src/protocols/vnc/client.c @@ -69,7 +69,8 @@ const char* GUAC_CLIENT_ARGS[] = { #endif #ifdef ENABLE_PULSE - "disable-audio", + "enable-audio", + "audio-servername", #endif NULL @@ -91,7 +92,8 @@ enum VNC_ARGS_IDX { #endif #ifdef ENABLE_PULSE - IDX_DISABLE_AUDIO, + IDX_ENABLE_AUDIO, + IDX_AUDIO_SERVERNAME, #endif VNC_ARGS_COUNT @@ -161,13 +163,21 @@ int guac_client_init(guac_client* client, int argc, char** argv) { guac_vnc_set_pixel_format(rfb_client, atoi(argv[IDX_COLOR_DEPTH])); #ifdef ENABLE_PULSE - guac_client_data->audio_enabled = (strcmp(argv[IDX_DISABLE_AUDIO], "true") != 0); + guac_client_data->audio_enabled = + (strcmp(argv[IDX_ENABLE_AUDIO], "true") == 0); /* If an encoding is available, load an audio stream */ if (guac_client_data->audio_enabled) { guac_client_data->audio = guac_audio_stream_alloc(client, NULL); + /* Load servername if specified */ + if (argv[IDX_AUDIO_SERVERNAME][0] != '\0') + guac_client_data->pa_servername = + strdup(argv[IDX_AUDIO_SERVERNAME]); + else + guac_client_data->pa_servername = NULL; + /* If successful, init audio system */ if (guac_client_data->audio != NULL) { diff --git a/src/protocols/vnc/client.h b/src/protocols/vnc/client.h index 176f00eb..4bf63c8d 100644 --- a/src/protocols/vnc/client.h +++ b/src/protocols/vnc/client.h @@ -68,6 +68,11 @@ typedef struct vnc_guac_client_data { */ guac_audio_stream* audio; + /** + * The name of the PulseAudio server to connect to. + */ + char* pa_servername; + /** * PulseAudio event loop. */ diff --git a/src/protocols/vnc/pulse.c b/src/protocols/vnc/pulse.c index e9ce0ebf..da357ed7 100644 --- a/src/protocols/vnc/pulse.c +++ b/src/protocols/vnc/pulse.c @@ -41,6 +41,7 @@ #include #include "client.h" +#include "pulse.h" static void __stream_read_callback(pa_stream* stream, size_t length, void* data) { @@ -58,9 +59,12 @@ static void __stream_read_callback(pa_stream* stream, size_t length, guac_audio_stream_write_pcm(audio, buffer, length); /* Flush occasionally */ - if (audio->pcm_bytes_written > 10000) { + if (audio->pcm_bytes_written > GUAC_VNC_PCM_WRITE_RATE) { guac_audio_stream_end(audio); - guac_audio_stream_begin(client_data->audio, 44100, 2, 16); + guac_audio_stream_begin(client_data->audio, + GUAC_VNC_AUDIO_RATE, + GUAC_VNC_AUDIO_CHANNELS, + GUAC_VNC_AUDIO_BPS); } /* Advance buffer */ @@ -110,6 +114,7 @@ static void __context_get_sink_info_callback(pa_context* context, guac_client* client = (guac_client*) data; pa_stream* stream; pa_sample_spec spec; + pa_buffer_attr attr; /* Stop if end of list reached */ if (is_last) @@ -120,8 +125,11 @@ static void __context_get_sink_info_callback(pa_context* context, /* Set format */ spec.format = PA_SAMPLE_S16LE; - spec.rate = 44100; - spec.channels = 2; + spec.rate = GUAC_VNC_AUDIO_RATE; + spec.channels = GUAC_VNC_AUDIO_CHANNELS; + + attr.maxlength = GUAC_VNC_AUDIO_BUFFER_SIZE; + attr.fragsize = attr.maxlength; /* Create stream */ stream = pa_stream_new(context, "Guacamole Audio", &spec, NULL); @@ -131,8 +139,9 @@ static void __context_get_sink_info_callback(pa_context* context, pa_stream_set_read_callback(stream, __stream_read_callback, client); /* Start stream */ - pa_stream_connect_record(stream, info->monitor_source_name, NULL, - PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND); + pa_stream_connect_record(stream, info->monitor_source_name, &attr, + PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND + | PA_STREAM_ADJUST_LATENCY); } @@ -211,7 +220,10 @@ void guac_pa_start_stream(guac_client* client) { pa_context* context; guac_client_log_info(client, "Starting audio stream"); - guac_audio_stream_begin(client_data->audio, 44100, 2, 16); + guac_audio_stream_begin(client_data->audio, + GUAC_VNC_AUDIO_RATE, + GUAC_VNC_AUDIO_CHANNELS, + GUAC_VNC_AUDIO_BPS); /* Init main loop */ client_data->pa_mainloop = pa_threaded_mainloop_new(); @@ -223,7 +235,8 @@ void guac_pa_start_stream(guac_client* client) { /* Set up context */ pa_context_set_state_callback(context, __context_state_callback, client); - pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); + pa_context_connect(context, client_data->pa_servername, + PA_CONTEXT_NOAUTOSPAWN, NULL); /* Start loop */ pa_threaded_mainloop_start(client_data->pa_mainloop); diff --git a/src/protocols/vnc/pulse.h b/src/protocols/vnc/pulse.h index 7f7e587e..4d968171 100644 --- a/src/protocols/vnc/pulse.h +++ b/src/protocols/vnc/pulse.h @@ -38,6 +38,32 @@ #ifndef __GUAC_VNC_PULSE_H #define __GUAC_VNC_PULSE_H +/** + * The number of bytes to request for the PulseAudio buffers. + */ +#define GUAC_VNC_AUDIO_BUFFER_SIZE 10240 + +/** + * The minimum number of PCM bytes to wait for before flushing an audio + * packet. + */ +#define GUAC_VNC_PCM_WRITE_RATE 10240 + +/** + * Rate of audio to stream, in Hz. + */ +#define GUAC_VNC_AUDIO_RATE 44100 + +/** + * The number of channels to stream. + */ +#define GUAC_VNC_AUDIO_CHANNELS 2 + +/** + * The number of bits per sample. + */ +#define GUAC_VNC_AUDIO_BPS 16 + /** * Starts streaming audio from PulseAudio to the given Guacamole client. *