GUACAMOLE-179: Use non-owner users of connection to determine audio encoding if necessary.

This commit is contained in:
Michael Jumper 2016-12-26 13:49:04 -08:00
parent 48ebbe95ea
commit 440668a78a
3 changed files with 64 additions and 42 deletions

View File

@ -30,16 +30,38 @@
#include <stdlib.h>
#include <string.h>
/**
* Sets the encoder associated with the given guac_audio_stream, automatically
* invoking its begin_handler. The guac_audio_stream MUST NOT already be
* associated with an encoder.
*
* @param audio
* The guac_audio_stream whose encoder is being set.
*
* @param encoder
* The encoder to associate with the given guac_audio_stream.
*/
static void guac_audio_stream_set_encoder(guac_audio_stream* audio,
guac_audio_encoder* encoder) {
/* Call handler, if defined */
if (encoder != NULL && encoder->begin_handler)
encoder->begin_handler(audio);
/* Assign encoder, which may be NULL */
audio->encoder = encoder;
}
/**
* Assigns a new audio encoder to the given guac_audio_stream based on the
* audio mimetypes declared as supported by the given user. If no audio encoder
* can be found, no new audio encoder is assigned, and the existing encoder is
* left untouched (if any).
*
* @param owner
* @param user
* The user whose supported audio mimetypes should determine the audio
* encoder selected. It is expected that this user will be the owner of
* the connection.
* encoder selected.
*
* @param data
* The guac_audio_stream to which the new encoder should be assigned.
@ -50,31 +72,32 @@
* The assigned audio encoder. If no new audio encoder can be assigned,
* this will be the currently-assigned audio encoder (which may be NULL).
*/
static void* guac_audio_assign_encoder(guac_user* owner, void* data) {
static void* guac_audio_assign_encoder(guac_user* user, void* data) {
int i;
guac_audio_stream* audio = (guac_audio_stream*) data;
int bps = audio->bps;
/* If there is no owner, do not attempt to assign a new encoder */
if (owner == NULL)
/* If no user is provided, or an encoder has already been assigned,
* do not attempt to assign a new encoder */
if (user == NULL || audio->encoder != NULL)
return audio->encoder;
/* For each supported mimetype, check for an associated encoder */
for (i=0; owner->info.audio_mimetypes[i] != NULL; i++) {
for (i=0; user->info.audio_mimetypes[i] != NULL; i++) {
const char* mimetype = owner->info.audio_mimetypes[i];
const char* mimetype = user->info.audio_mimetypes[i];
/* If 16-bit raw audio is supported, done. */
if (bps == 16 && strcmp(mimetype, raw16_encoder->mimetype) == 0) {
audio->encoder = raw16_encoder;
guac_audio_stream_set_encoder(audio, raw16_encoder);
break;
}
/* If 8-bit raw audio is supported, done. */
if (bps == 8 && strcmp(mimetype, raw8_encoder->mimetype) == 0) {
audio->encoder = raw8_encoder;
guac_audio_stream_set_encoder(audio, raw8_encoder);
break;
}
@ -100,16 +123,17 @@ guac_audio_stream* guac_audio_stream_alloc(guac_client* client,
audio->channels = channels;
audio->bps = bps;
/* Assign encoder for owner, abort if no encoder can be found */
if (!guac_client_for_owner(client, guac_audio_assign_encoder, audio)) {
guac_client_free_stream(client, audio->stream);
free(audio);
return NULL;
}
/* Assign encoder if explicitly provided */
if (encoder != NULL)
guac_audio_stream_set_encoder(audio, encoder);
/* Call handler, if defined */
if (audio->encoder->begin_handler)
audio->encoder->begin_handler(audio);
/* Otherwise, attempt to automatically assign encoder for owner */
if (audio->encoder == NULL)
guac_client_for_owner(client, guac_audio_assign_encoder, audio);
/* Failing that, attempt to assign encoder for ANY connected user */
if (audio->encoder == NULL)
guac_client_foreach_user(client, guac_audio_assign_encoder, audio);
return audio;
@ -118,8 +142,12 @@ guac_audio_stream* guac_audio_stream_alloc(guac_client* client,
void guac_audio_stream_reset(guac_audio_stream* audio,
guac_audio_encoder* encoder, int rate, int channels, int bps) {
/* Pull assigned encoder if no other encoder is requested */
if (encoder == NULL)
encoder = audio->encoder;
/* Do nothing if nothing is changing */
if ((encoder == NULL || encoder == audio->encoder)
if (encoder == audio->encoder
&& rate == audio->rate
&& channels == audio->channels
&& bps == audio->bps) {
@ -127,31 +155,28 @@ void guac_audio_stream_reset(guac_audio_stream* audio,
}
/* Free old encoder data */
if (audio->encoder->end_handler)
if (audio->encoder != NULL && audio->encoder->end_handler)
audio->encoder->end_handler(audio);
/* Assign new encoder, if changed */
if (encoder != NULL)
audio->encoder = encoder;
/* Set PCM properties */
audio->rate = rate;
audio->channels = channels;
audio->bps = bps;
/* Init encoder with new data */
if (audio->encoder->begin_handler)
audio->encoder->begin_handler(audio);
/* Re-init encoder */
guac_audio_stream_set_encoder(audio, encoder);
}
void guac_audio_stream_add_user(guac_audio_stream* audio, guac_user* user) {
guac_audio_encoder* encoder = audio->encoder;
/* Attempt to assign encoder if no encoder has yet been assigned */
if (audio->encoder == NULL)
guac_audio_assign_encoder(user, audio);
/* Notify encoder that a new user is present */
if (encoder->join_handler)
encoder->join_handler(audio, user);
if (audio->encoder != NULL && audio->encoder->join_handler)
audio->encoder->join_handler(audio, user);
}
@ -161,7 +186,7 @@ void guac_audio_stream_free(guac_audio_stream* audio) {
guac_audio_stream_flush(audio);
/* Clean up encoder */
if (audio->encoder->end_handler)
if (audio->encoder != NULL && audio->encoder->end_handler)
audio->encoder->end_handler(audio);
/* Free associated data */
@ -173,7 +198,7 @@ void guac_audio_stream_write_pcm(guac_audio_stream* audio,
const unsigned char* data, int length) {
/* Write data */
if (audio->encoder->write_handler)
if (audio->encoder != NULL && audio->encoder->write_handler)
audio->encoder->write_handler(audio, data, length);
}
@ -181,7 +206,7 @@ void guac_audio_stream_write_pcm(guac_audio_stream* audio,
void guac_audio_stream_flush(guac_audio_stream* audio) {
/* Flush any buffered data */
if (audio->encoder->flush_handler)
if (audio->encoder != NULL && audio->encoder->flush_handler)
audio->encoder->flush_handler(audio);
}

View File

@ -114,7 +114,7 @@ struct guac_audio_stream {
* Allocates a new audio stream at the client level which encodes audio data
* using the given encoder. If NULL is specified for the encoder, an
* appropriate encoder will be selected based on the encoders built into
* libguac and the level of support declared by the owner associated with the
* libguac and the level of support declared by users associated with the
* given guac_client. The PCM format specified here (via rate, channels, and
* bps) must be the format used for all PCM data provided to the audio stream.
* The format may only be changed using guac_audio_stream_reset().
@ -125,10 +125,10 @@ struct guac_audio_stream {
* for the new user.
*
* @param client
* The guac_client for which this audio stream is being allocated. Only the
* connection owner is used to determine the level of audio support, and it
* is currently assumed that all other joining users on the connection will
* have the same level of audio support.
* The guac_client for which this audio stream is being allocated. The
* connection owner is given priority when determining the level of audio
* support. It is currently assumed that all other joining users on the
* connection will have the same level of audio support.
*
* @param encoder
* The guac_audio_encoder to use when encoding audio, or NULL if libguac

View File

@ -236,9 +236,6 @@ guac_pa_stream* guac_pa_stream_alloc(guac_client* client,
if (audio == NULL)
return NULL;
guac_client_log(client, GUAC_LOG_INFO, "Audio will be encoded as %s",
audio->encoder->mimetype);
/* Init main loop */
guac_pa_stream* stream = malloc(sizeof(guac_pa_stream));
stream->client = client;