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 <stdlib.h>
#include <string.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 * 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 * 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 * can be found, no new audio encoder is assigned, and the existing encoder is
* left untouched (if any). * left untouched (if any).
* *
* @param owner * @param user
* The user whose supported audio mimetypes should determine the audio * The user whose supported audio mimetypes should determine the audio
* encoder selected. It is expected that this user will be the owner of * encoder selected.
* the connection.
* *
* @param data * @param data
* The guac_audio_stream to which the new encoder should be assigned. * 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, * The assigned audio encoder. If no new audio encoder can be assigned,
* this will be the currently-assigned audio encoder (which may be NULL). * 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; int i;
guac_audio_stream* audio = (guac_audio_stream*) data; guac_audio_stream* audio = (guac_audio_stream*) data;
int bps = audio->bps; int bps = audio->bps;
/* If there is no owner, do not attempt to assign a new encoder */ /* If no user is provided, or an encoder has already been assigned,
if (owner == NULL) * do not attempt to assign a new encoder */
if (user == NULL || audio->encoder != NULL)
return audio->encoder; return audio->encoder;
/* For each supported mimetype, check for an associated 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 16-bit raw audio is supported, done. */
if (bps == 16 && strcmp(mimetype, raw16_encoder->mimetype) == 0) { if (bps == 16 && strcmp(mimetype, raw16_encoder->mimetype) == 0) {
audio->encoder = raw16_encoder; guac_audio_stream_set_encoder(audio, raw16_encoder);
break; break;
} }
/* If 8-bit raw audio is supported, done. */ /* If 8-bit raw audio is supported, done. */
if (bps == 8 && strcmp(mimetype, raw8_encoder->mimetype) == 0) { if (bps == 8 && strcmp(mimetype, raw8_encoder->mimetype) == 0) {
audio->encoder = raw8_encoder; guac_audio_stream_set_encoder(audio, raw8_encoder);
break; break;
} }
@ -100,16 +123,17 @@ guac_audio_stream* guac_audio_stream_alloc(guac_client* client,
audio->channels = channels; audio->channels = channels;
audio->bps = bps; audio->bps = bps;
/* Assign encoder for owner, abort if no encoder can be found */ /* Assign encoder if explicitly provided */
if (!guac_client_for_owner(client, guac_audio_assign_encoder, audio)) { if (encoder != NULL)
guac_client_free_stream(client, audio->stream); guac_audio_stream_set_encoder(audio, encoder);
free(audio);
return NULL;
}
/* Call handler, if defined */ /* Otherwise, attempt to automatically assign encoder for owner */
if (audio->encoder->begin_handler) if (audio->encoder == NULL)
audio->encoder->begin_handler(audio); 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; 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, void guac_audio_stream_reset(guac_audio_stream* audio,
guac_audio_encoder* encoder, int rate, int channels, int bps) { 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 */ /* Do nothing if nothing is changing */
if ((encoder == NULL || encoder == audio->encoder) if (encoder == audio->encoder
&& rate == audio->rate && rate == audio->rate
&& channels == audio->channels && channels == audio->channels
&& bps == audio->bps) { && bps == audio->bps) {
@ -127,31 +155,28 @@ void guac_audio_stream_reset(guac_audio_stream* audio,
} }
/* Free old encoder data */ /* Free old encoder data */
if (audio->encoder->end_handler) if (audio->encoder != NULL && audio->encoder->end_handler)
audio->encoder->end_handler(audio); audio->encoder->end_handler(audio);
/* Assign new encoder, if changed */
if (encoder != NULL)
audio->encoder = encoder;
/* Set PCM properties */ /* Set PCM properties */
audio->rate = rate; audio->rate = rate;
audio->channels = channels; audio->channels = channels;
audio->bps = bps; audio->bps = bps;
/* Init encoder with new data */ /* Re-init encoder */
if (audio->encoder->begin_handler) guac_audio_stream_set_encoder(audio, encoder);
audio->encoder->begin_handler(audio);
} }
void guac_audio_stream_add_user(guac_audio_stream* audio, guac_user* user) { 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 */ /* Notify encoder that a new user is present */
if (encoder->join_handler) if (audio->encoder != NULL && audio->encoder->join_handler)
encoder->join_handler(audio, user); audio->encoder->join_handler(audio, user);
} }
@ -161,7 +186,7 @@ void guac_audio_stream_free(guac_audio_stream* audio) {
guac_audio_stream_flush(audio); guac_audio_stream_flush(audio);
/* Clean up encoder */ /* Clean up encoder */
if (audio->encoder->end_handler) if (audio->encoder != NULL && audio->encoder->end_handler)
audio->encoder->end_handler(audio); audio->encoder->end_handler(audio);
/* Free associated data */ /* Free associated data */
@ -173,7 +198,7 @@ void guac_audio_stream_write_pcm(guac_audio_stream* audio,
const unsigned char* data, int length) { const unsigned char* data, int length) {
/* Write data */ /* Write data */
if (audio->encoder->write_handler) if (audio->encoder != NULL && audio->encoder->write_handler)
audio->encoder->write_handler(audio, data, length); 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) { void guac_audio_stream_flush(guac_audio_stream* audio) {
/* Flush any buffered data */ /* Flush any buffered data */
if (audio->encoder->flush_handler) if (audio->encoder != NULL && audio->encoder->flush_handler)
audio->encoder->flush_handler(audio); 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 * 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 * using the given encoder. If NULL is specified for the encoder, an
* appropriate encoder will be selected based on the encoders built into * 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 * 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. * 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(). * The format may only be changed using guac_audio_stream_reset().
@ -125,10 +125,10 @@ struct guac_audio_stream {
* for the new user. * for the new user.
* *
* @param client * @param client
* The guac_client for which this audio stream is being allocated. Only the * The guac_client for which this audio stream is being allocated. The
* connection owner is used to determine the level of audio support, and it * connection owner is given priority when determining the level of audio
* is currently assumed that all other joining users on the connection will * support. It is currently assumed that all other joining users on the
* have the same level of audio support. * connection will have the same level of audio support.
* *
* @param encoder * @param encoder
* The guac_audio_encoder to use when encoding audio, or NULL if libguac * 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) if (audio == NULL)
return NULL; return NULL;
guac_client_log(client, GUAC_LOG_INFO, "Audio will be encoded as %s",
audio->encoder->mimetype);
/* Init main loop */ /* Init main loop */
guac_pa_stream* stream = malloc(sizeof(guac_pa_stream)); guac_pa_stream* stream = malloc(sizeof(guac_pa_stream));
stream->client = client; stream->client = client;