From f482f83eb893314dbfe84ec04b017c7c469d8ca3 Mon Sep 17 00:00:00 2001 From: Eric Wollesen Date: Fri, 12 Sep 2008 15:57:43 +0200 Subject: shout: added shout_buffer The Ogg encoder is slightly less optimal under this configuration. It used to send shout data directly out of its ogg_page structures. Now, in the interest of encapsulation, it copies the data from its ogg_page structures into a buffer provided by the shout audio output plugin (see audioOutput_shout_ogg.c, line 77.) I suspect the performance impact is negligible. [mk: this patch and its description was separated from Eric's patch "Refactor and cleanup of shout Ogg and MP3 audio outputs"] --- src/audioOutputs/audioOutput_shout.c | 54 ++++++++++----------- src/audioOutputs/audioOutput_shout.h | 14 ++++-- src/audioOutputs/audioOutput_shout_ogg.c | 80 +++++++++++++++++++++++++------- 3 files changed, 102 insertions(+), 46 deletions(-) (limited to 'src/audioOutputs') diff --git a/src/audioOutputs/audioOutput_shout.c b/src/audioOutputs/audioOutput_shout.c index 16119a80f..7c11cb7e2 100644 --- a/src/audioOutputs/audioOutput_shout.c +++ b/src/audioOutputs/audioOutput_shout.c @@ -25,8 +25,16 @@ #define CONN_ATTEMPT_INTERVAL 60 #define DEFAULT_CONN_TIMEOUT 2 +#define SHOUT_BUF_SIZE 8192 + static int shout_init_count; +static void clear_shout_buffer(struct shout_data * sd) +{ + sd->buf.len = 0; + sd->buf.data[0] = '\0'; +} + static struct shout_data *new_shout_data(void) { struct shout_data *ret = xmalloc(sizeof(*ret)); @@ -41,6 +49,10 @@ static struct shout_data *new_shout_data(void) ret->conn_attempts = 0; ret->last_attempt = 0; ret->timer = NULL; + ret->buf.data = xmalloc(sizeof(unsigned char) * + SHOUT_BUF_SIZE); + ret->buf.max_len = SHOUT_BUF_SIZE; + clear_shout_buffer(ret); return ret; } @@ -51,6 +63,8 @@ static void free_shout_data(struct shout_data *sd) shout_free(sd->shout_conn); if (sd->tag) tag_free(sd->tag); + if (sd->buf.data) + free(sd->buf.data); if (sd->timer) timer_free(sd->timer); @@ -248,25 +262,25 @@ static int handle_shout_error(struct shout_data *sd, int err) return 0; } -int write_page(struct shout_data *sd) +static int write_page(struct shout_data *sd) { int err; shout_sync(sd->shout_conn); - err = shout_send(sd->shout_conn, sd->og.header, sd->og.header_len); - if (handle_shout_error(sd, err) < 0) - return -1; - err = shout_send(sd->shout_conn, sd->og.body, sd->og.body_len); + err = shout_send(sd->shout_conn, sd->buf.data, sd->buf.len); if (handle_shout_error(sd, err) < 0) return -1; + clear_shout_buffer(sd); return 0; } static void close_shout_conn(struct shout_data *sd) { - if (sd->opened) - shout_ogg_encoder_clear_encoder(sd); + if (sd->opened) { + if (shout_ogg_encoder_clear_encoder(sd)) + write_page(sd); + } if (shout_get_connected(sd->shout_conn) != SHOUTERR_UNCONNECTED && shout_close(sd->shout_conn) != SHOUTERR_SUCCESS) { @@ -383,22 +397,12 @@ static int open_shout_conn(struct audio_output *audio_output) return -1; } - sd->shout_error = 0; - - copy_tag_to_vorbis_comment(sd); - - send_ogg_vorbis_header(sd); + if (sd->buf.len) + write_page(sd); + sd->shout_error = 0; sd->opened = 1; - sd->tag_to_send = 0; - - while (ogg_stream_flush(&(sd->os), &(sd->og))) { - if (write_page(sd) < 0) { - close_shout_conn(sd); - return -1; - } - } - + sd->tag_to_send = 1; sd->conn_attempts = 0; return 0; @@ -461,11 +465,9 @@ static int my_shout_play(struct audio_output *audio_output, shout_ogg_encoder_encode(sd, chunk, size); - while (ogg_stream_pageout(&(sd->os), &(sd->og)) != 0) { - if (write_page(sd) < 0) { - my_shout_close_device(audio_output); - return -1; - } + if (write_page(sd) < 0) { + my_shout_close_device(audio_output); + return -1; } return 0; diff --git a/src/audioOutputs/audioOutput_shout.h b/src/audioOutputs/audioOutput_shout.h index a68a40875..f145d7566 100644 --- a/src/audioOutputs/audioOutput_shout.h +++ b/src/audioOutputs/audioOutput_shout.h @@ -29,6 +29,12 @@ #include #include +typedef struct _shout_buffer { + unsigned char *data; + size_t len; + size_t max_len; +} shout_buffer; + struct shout_data { shout_t *shout_conn; int shout_error; @@ -61,15 +67,15 @@ struct shout_data { /* the configured audio format */ struct audio_format audio_format; -}; -int write_page(struct shout_data *sd); + shout_buffer buf; +}; void copy_tag_to_vorbis_comment(struct shout_data *sd); -void send_ogg_vorbis_header(struct shout_data *sd); +int send_ogg_vorbis_header(struct shout_data *sd); -void shout_ogg_encoder_clear_encoder(struct shout_data *sd); +int shout_ogg_encoder_clear_encoder(struct shout_data *sd); int init_encoder(struct shout_data *sd); diff --git a/src/audioOutputs/audioOutput_shout_ogg.c b/src/audioOutputs/audioOutput_shout_ogg.c index 8e7db7eed..cda6e5533 100644 --- a/src/audioOutputs/audioOutput_shout_ogg.c +++ b/src/audioOutputs/audioOutput_shout_ogg.c @@ -54,7 +54,42 @@ void copy_tag_to_vorbis_comment(struct shout_data *sd) } } -void send_ogg_vorbis_header(struct shout_data *sd) +static int copy_ogg_buffer_to_shout_buffer(ogg_page *og, + shout_buffer *buf) +{ + if (buf->max_len - buf->len >= (size_t)og->header_len) { + memcpy(buf->data + buf->len, + og->header, og->header_len); + buf->len += og->header_len; + } else { + ERROR("%s: not enough buffer space!\n", __func__); + return -1; + } + + if (buf->max_len - buf->len >= (size_t)og->body_len) { + memcpy(buf->data + buf->len, + og->body, og->body_len); + buf->len += og->body_len; + } else { + ERROR("%s: not enough buffer space!\n", __func__); + return -1; + } + + return 0; +} + +static int flush_ogg_buffer(struct shout_data *sd) +{ + shout_buffer *buf = &sd->buf; + int ret = 0; + + if (ogg_stream_flush(&sd->os, &sd->og)) + ret = copy_ogg_buffer_to_shout_buffer(&sd->og, buf); + + return ret; +} + +int send_ogg_vorbis_header(struct shout_data *sd) { vorbis_analysis_headerout(&(sd->vd), &(sd->vc), &(sd->header_main), &(sd->header_comments), @@ -63,6 +98,8 @@ void send_ogg_vorbis_header(struct shout_data *sd) ogg_stream_packetin(&(sd->os), &(sd->header_main)); ogg_stream_packetin(&(sd->os), &(sd->header_comments)); ogg_stream_packetin(&(sd->os), &(sd->header_codebooks)); + + return flush_ogg_buffer(sd); } static void finish_encoder(struct shout_data *sd) @@ -78,27 +115,24 @@ static void finish_encoder(struct shout_data *sd) } } -static int flush_encoder(struct shout_data *sd) +int shout_ogg_encoder_clear_encoder(struct shout_data *sd) { - return (ogg_stream_pageout(&sd->os, &sd->og) > 0); -} + int ret; -void shout_ogg_encoder_clear_encoder(struct shout_data *sd) -{ finish_encoder(sd); - while (1 == flush_encoder(sd)) { - if (!sd->shout_error) - write_page(sd); - } + if ((ret = ogg_stream_pageout(&sd->os, &sd->og))) + copy_ogg_buffer_to_shout_buffer(&sd->og, &sd->buf); vorbis_comment_clear(&sd->vc); ogg_stream_clear(&sd->os); vorbis_block_clear(&sd->vb); vorbis_dsp_clear(&sd->vd); vorbis_info_clear(&sd->vi); + + return ret; } -int init_encoder(struct shout_data *sd) +static int reinit_encoder(struct shout_data *sd) { vorbis_info_init(&(sd->vi)); @@ -130,10 +164,23 @@ int init_encoder(struct shout_data *sd) return 0; } +int init_encoder(struct shout_data *sd) +{ + if (reinit_encoder(sd)) + return -1; + + if (send_ogg_vorbis_header(sd)) { + ERROR("error sending ogg vorbis header for shout\n"); + return -1; + } + + return 0; +} + int shout_ogg_encoder_send_metadata(struct shout_data * sd) { shout_ogg_encoder_clear_encoder(sd); - if (init_encoder(sd) < 0) + if (reinit_encoder(sd)) return 0; copy_tag_to_vorbis_comment(sd); @@ -146,10 +193,7 @@ int shout_ogg_encoder_send_metadata(struct shout_data * sd) ogg_stream_packetin(&(sd->os), &(sd->header_comments)); ogg_stream_packetin(&(sd->os), &(sd->header_codebooks)); - while (ogg_stream_flush(&sd->os, &sd->og)) { - if (write_page(sd) < 0) - return -1; - } + flush_ogg_buffer(sd); return 0; } @@ -157,6 +201,7 @@ int shout_ogg_encoder_send_metadata(struct shout_data * sd) void shout_ogg_encoder_encode(struct shout_data *sd, const char *chunk, size_t size) { + shout_buffer *buf = &sd->buf; unsigned int i; int j; float **vorbbuf; @@ -185,6 +230,9 @@ void shout_ogg_encoder_encode(struct shout_data *sd, ogg_stream_packetin(&(sd->os), &(sd->op)); } } + + if (ogg_stream_pageout(&sd->os, &sd->og)) + copy_ogg_buffer_to_shout_buffer(&sd->og, buf); } #endif -- cgit v1.2.3