Commit f482f83e authored by Eric Wollesen's avatar Eric Wollesen Committed by Max Kellermann

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"]
parent fcac05a2
...@@ -25,8 +25,16 @@ ...@@ -25,8 +25,16 @@
#define CONN_ATTEMPT_INTERVAL 60 #define CONN_ATTEMPT_INTERVAL 60
#define DEFAULT_CONN_TIMEOUT 2 #define DEFAULT_CONN_TIMEOUT 2
#define SHOUT_BUF_SIZE 8192
static int shout_init_count; 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) static struct shout_data *new_shout_data(void)
{ {
struct shout_data *ret = xmalloc(sizeof(*ret)); struct shout_data *ret = xmalloc(sizeof(*ret));
...@@ -41,6 +49,10 @@ static struct shout_data *new_shout_data(void) ...@@ -41,6 +49,10 @@ static struct shout_data *new_shout_data(void)
ret->conn_attempts = 0; ret->conn_attempts = 0;
ret->last_attempt = 0; ret->last_attempt = 0;
ret->timer = NULL; 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; return ret;
} }
...@@ -51,6 +63,8 @@ static void free_shout_data(struct shout_data *sd) ...@@ -51,6 +63,8 @@ static void free_shout_data(struct shout_data *sd)
shout_free(sd->shout_conn); shout_free(sd->shout_conn);
if (sd->tag) if (sd->tag)
tag_free(sd->tag); tag_free(sd->tag);
if (sd->buf.data)
free(sd->buf.data);
if (sd->timer) if (sd->timer)
timer_free(sd->timer); timer_free(sd->timer);
...@@ -248,25 +262,25 @@ static int handle_shout_error(struct shout_data *sd, int err) ...@@ -248,25 +262,25 @@ static int handle_shout_error(struct shout_data *sd, int err)
return 0; return 0;
} }
int write_page(struct shout_data *sd) static int write_page(struct shout_data *sd)
{ {
int err; int err;
shout_sync(sd->shout_conn); shout_sync(sd->shout_conn);
err = shout_send(sd->shout_conn, sd->og.header, sd->og.header_len); err = shout_send(sd->shout_conn, sd->buf.data, sd->buf.len);
if (handle_shout_error(sd, err) < 0)
return -1;
err = shout_send(sd->shout_conn, sd->og.body, sd->og.body_len);
if (handle_shout_error(sd, err) < 0) if (handle_shout_error(sd, err) < 0)
return -1; return -1;
clear_shout_buffer(sd);
return 0; return 0;
} }
static void close_shout_conn(struct shout_data *sd) static void close_shout_conn(struct shout_data *sd)
{ {
if (sd->opened) if (sd->opened) {
shout_ogg_encoder_clear_encoder(sd); if (shout_ogg_encoder_clear_encoder(sd))
write_page(sd);
}
if (shout_get_connected(sd->shout_conn) != SHOUTERR_UNCONNECTED && if (shout_get_connected(sd->shout_conn) != SHOUTERR_UNCONNECTED &&
shout_close(sd->shout_conn) != SHOUTERR_SUCCESS) { shout_close(sd->shout_conn) != SHOUTERR_SUCCESS) {
...@@ -383,22 +397,12 @@ static int open_shout_conn(struct audio_output *audio_output) ...@@ -383,22 +397,12 @@ static int open_shout_conn(struct audio_output *audio_output)
return -1; return -1;
} }
sd->shout_error = 0; if (sd->buf.len)
write_page(sd);
copy_tag_to_vorbis_comment(sd);
send_ogg_vorbis_header(sd);
sd->shout_error = 0;
sd->opened = 1; sd->opened = 1;
sd->tag_to_send = 0; sd->tag_to_send = 1;
while (ogg_stream_flush(&(sd->os), &(sd->og))) {
if (write_page(sd) < 0) {
close_shout_conn(sd);
return -1;
}
}
sd->conn_attempts = 0; sd->conn_attempts = 0;
return 0; return 0;
...@@ -461,12 +465,10 @@ static int my_shout_play(struct audio_output *audio_output, ...@@ -461,12 +465,10 @@ static int my_shout_play(struct audio_output *audio_output,
shout_ogg_encoder_encode(sd, chunk, size); shout_ogg_encoder_encode(sd, chunk, size);
while (ogg_stream_pageout(&(sd->os), &(sd->og)) != 0) {
if (write_page(sd) < 0) { if (write_page(sd) < 0) {
my_shout_close_device(audio_output); my_shout_close_device(audio_output);
return -1; return -1;
} }
}
return 0; return 0;
} }
......
...@@ -29,6 +29,12 @@ ...@@ -29,6 +29,12 @@
#include <shout/shout.h> #include <shout/shout.h>
#include <vorbis/vorbisenc.h> #include <vorbis/vorbisenc.h>
typedef struct _shout_buffer {
unsigned char *data;
size_t len;
size_t max_len;
} shout_buffer;
struct shout_data { struct shout_data {
shout_t *shout_conn; shout_t *shout_conn;
int shout_error; int shout_error;
...@@ -61,15 +67,15 @@ struct shout_data { ...@@ -61,15 +67,15 @@ struct shout_data {
/* the configured audio format */ /* the configured audio format */
struct audio_format 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 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); int init_encoder(struct shout_data *sd);
......
...@@ -54,7 +54,42 @@ void copy_tag_to_vorbis_comment(struct shout_data *sd) ...@@ -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), vorbis_analysis_headerout(&(sd->vd), &(sd->vc), &(sd->header_main),
&(sd->header_comments), &(sd->header_comments),
...@@ -63,6 +98,8 @@ void send_ogg_vorbis_header(struct shout_data *sd) ...@@ -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_main));
ogg_stream_packetin(&(sd->os), &(sd->header_comments)); ogg_stream_packetin(&(sd->os), &(sd->header_comments));
ogg_stream_packetin(&(sd->os), &(sd->header_codebooks)); ogg_stream_packetin(&(sd->os), &(sd->header_codebooks));
return flush_ogg_buffer(sd);
} }
static void finish_encoder(struct shout_data *sd) static void finish_encoder(struct shout_data *sd)
...@@ -78,27 +115,24 @@ 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); finish_encoder(sd);
while (1 == flush_encoder(sd)) { if ((ret = ogg_stream_pageout(&sd->os, &sd->og)))
if (!sd->shout_error) copy_ogg_buffer_to_shout_buffer(&sd->og, &sd->buf);
write_page(sd);
}
vorbis_comment_clear(&sd->vc); vorbis_comment_clear(&sd->vc);
ogg_stream_clear(&sd->os); ogg_stream_clear(&sd->os);
vorbis_block_clear(&sd->vb); vorbis_block_clear(&sd->vb);
vorbis_dsp_clear(&sd->vd); vorbis_dsp_clear(&sd->vd);
vorbis_info_clear(&sd->vi); 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)); vorbis_info_init(&(sd->vi));
...@@ -130,10 +164,23 @@ int init_encoder(struct shout_data *sd) ...@@ -130,10 +164,23 @@ int init_encoder(struct shout_data *sd)
return 0; 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) int shout_ogg_encoder_send_metadata(struct shout_data * sd)
{ {
shout_ogg_encoder_clear_encoder(sd); shout_ogg_encoder_clear_encoder(sd);
if (init_encoder(sd) < 0) if (reinit_encoder(sd))
return 0; return 0;
copy_tag_to_vorbis_comment(sd); copy_tag_to_vorbis_comment(sd);
...@@ -146,10 +193,7 @@ int shout_ogg_encoder_send_metadata(struct shout_data * 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_comments));
ogg_stream_packetin(&(sd->os), &(sd->header_codebooks)); ogg_stream_packetin(&(sd->os), &(sd->header_codebooks));
while (ogg_stream_flush(&sd->os, &sd->og)) { flush_ogg_buffer(sd);
if (write_page(sd) < 0)
return -1;
}
return 0; return 0;
} }
...@@ -157,6 +201,7 @@ int shout_ogg_encoder_send_metadata(struct shout_data * sd) ...@@ -157,6 +201,7 @@ int shout_ogg_encoder_send_metadata(struct shout_data * sd)
void shout_ogg_encoder_encode(struct shout_data *sd, void shout_ogg_encoder_encode(struct shout_data *sd,
const char *chunk, size_t size) const char *chunk, size_t size)
{ {
shout_buffer *buf = &sd->buf;
unsigned int i; unsigned int i;
int j; int j;
float **vorbbuf; float **vorbbuf;
...@@ -185,6 +230,9 @@ void shout_ogg_encoder_encode(struct shout_data *sd, ...@@ -185,6 +230,9 @@ void shout_ogg_encoder_encode(struct shout_data *sd,
ogg_stream_packetin(&(sd->os), &(sd->op)); 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 #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment