shout: switch to blocking mode

The non-blocking mode of libshout is sparsely documented, and MPD's
implementation had several bugs.  Also removed connect throttling
code, that is done by the MPD core since 0.14.
This commit is contained in:
Max Kellermann 2009-02-09 16:35:54 +01:00
parent cf94008b27
commit f6455d5f79
3 changed files with 8 additions and 77 deletions

1
NEWS
View File

@ -47,6 +47,7 @@ ver 0.14.2 (2009/??/??)
- jack: clear "shutdown" flag on reconnect - jack: clear "shutdown" flag on reconnect
- jack: reduced sleep time to 1ms - jack: reduced sleep time to 1ms
- shout: fixed memory leak in the mp3 encoder - shout: fixed memory leak in the mp3 encoder
- shout: switch to blocking mode
* mapper: remove trailing slashes from music_directory * mapper: remove trailing slashes from music_directory
* player: set player error when output device fails * player: set player error when output device fails

View File

@ -23,7 +23,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#define CONN_ATTEMPT_INTERVAL 60
#define DEFAULT_CONN_TIMEOUT 2 #define DEFAULT_CONN_TIMEOUT 2
static int shout_init_count; static int shout_init_count;
@ -56,13 +55,10 @@ static struct shout_data *new_shout_data(void)
ret->shout_conn = shout_new(); ret->shout_conn = shout_new();
ret->shout_meta = shout_metadata_new(); ret->shout_meta = shout_metadata_new();
ret->opened = 0;
ret->tag = NULL; ret->tag = NULL;
ret->bitrate = -1; ret->bitrate = -1;
ret->quality = -2.0; ret->quality = -2.0;
ret->timeout = DEFAULT_CONN_TIMEOUT; ret->timeout = DEFAULT_CONN_TIMEOUT;
ret->conn_attempts = 0;
ret->last_attempt = 0;
ret->timer = NULL; ret->timer = NULL;
ret->buf.len = 0; ret->buf.len = 0;
@ -210,7 +206,6 @@ static void *my_shout_init_driver(struct audio_output *audio_output,
shout_set_name(sd->shout_conn, name) != SHOUTERR_SUCCESS || shout_set_name(sd->shout_conn, name) != SHOUTERR_SUCCESS ||
shout_set_user(sd->shout_conn, user) != SHOUTERR_SUCCESS || shout_set_user(sd->shout_conn, user) != SHOUTERR_SUCCESS ||
shout_set_public(sd->shout_conn, public) != SHOUTERR_SUCCESS || shout_set_public(sd->shout_conn, public) != SHOUTERR_SUCCESS ||
shout_set_nonblocking(sd->shout_conn, 1) != SHOUTERR_SUCCESS ||
shout_set_format(sd->shout_conn, sd->encoder->shout_format) shout_set_format(sd->shout_conn, sd->encoder->shout_format)
!= SHOUTERR_SUCCESS || != SHOUTERR_SUCCESS ||
shout_set_protocol(sd->shout_conn, protocol) != SHOUTERR_SUCCESS || shout_set_protocol(sd->shout_conn, protocol) != SHOUTERR_SUCCESS ||
@ -305,26 +300,20 @@ static int write_page(struct shout_data *sd)
static void close_shout_conn(struct shout_data * sd) static void close_shout_conn(struct shout_data * sd)
{ {
if (sd->opened) { if (sd->encoder->clear_encoder_func(sd))
if (sd->encoder->clear_encoder_func(sd)) write_page(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) {
g_warning("problem closing connection to shout server: %s\n", g_warning("problem closing connection to shout server: %s\n",
shout_get_error(sd->shout_conn)); shout_get_error(sd->shout_conn));
} }
sd->opened = false;
} }
static void my_shout_finish_driver(void *data) static void my_shout_finish_driver(void *data)
{ {
struct shout_data *sd = (struct shout_data *)data; struct shout_data *sd = (struct shout_data *)data;
close_shout_conn(sd);
sd->encoder->finish_func(sd); sd->encoder->finish_func(sd);
free_shout_data(sd); free_shout_data(sd);
@ -356,56 +345,18 @@ static void my_shout_close_device(void *data)
static int shout_connect(struct shout_data *sd) static int shout_connect(struct shout_data *sd)
{ {
time_t t = time(NULL); int state;
int state = shout_get_connected(sd->shout_conn);
/* already connected */
if (state == SHOUTERR_CONNECTED)
return 0;
/* waiting to connect */
if (state == SHOUTERR_BUSY && sd->conn_attempts != 0) {
/* timeout waiting to connect */
if ((t - sd->last_attempt) > sd->timeout) {
g_warning("timeout connecting to shout server %s:%i "
"(attempt %i)\n",
shout_get_host(sd->shout_conn),
shout_get_port(sd->shout_conn),
sd->conn_attempts);
return -1;
}
return 1;
}
/* we're in some funky state, so just reset it to unconnected */
if (state != SHOUTERR_UNCONNECTED)
shout_close(sd->shout_conn);
/* throttle new connection attempts */
if (sd->conn_attempts != 0 &&
(t - sd->last_attempt) <= CONN_ATTEMPT_INTERVAL) {
return -1;
}
/* initiate a new connection */
sd->conn_attempts++;
sd->last_attempt = t;
state = shout_open(sd->shout_conn); state = shout_open(sd->shout_conn);
switch (state) { switch (state) {
case SHOUTERR_SUCCESS: case SHOUTERR_SUCCESS:
case SHOUTERR_CONNECTED: case SHOUTERR_CONNECTED:
return 0; return 0;
case SHOUTERR_BUSY:
return 1;
default: default:
g_warning("problem opening connection to shout server %s:%i " g_warning("problem opening connection to shout server %s:%i: %s\n",
"(attempt %i): %s\n",
shout_get_host(sd->shout_conn), shout_get_host(sd->shout_conn),
shout_get_port(sd->shout_conn), shout_get_port(sd->shout_conn),
sd->conn_attempts, shout_get_error(sd->shout_conn)); shout_get_error(sd->shout_conn));
return -1; return -1;
} }
} }
@ -426,9 +377,6 @@ static int open_shout_conn(void *data)
write_page(sd); write_page(sd);
sd->opened = true;
sd->conn_attempts = 0;
return 0; return 0;
} }
@ -437,7 +385,7 @@ static bool my_shout_open_device(void *data,
{ {
struct shout_data *sd = (struct shout_data *)data; struct shout_data *sd = (struct shout_data *)data;
if (!sd->opened && open_shout_conn(sd) < 0) if (open_shout_conn(sd) < 0)
return false; return false;
if (sd->timer) if (sd->timer)
@ -455,9 +403,6 @@ static void send_metadata(struct shout_data * sd)
assert(sd->tag != NULL); assert(sd->tag != NULL);
if (!sd->opened)
return;
if (sd->encoder->send_metadata_func(sd, song, size)) { if (sd->encoder->send_metadata_func(sd, song, size)) {
shout_metadata_add(sd->shout_meta, "song", song); shout_metadata_add(sd->shout_meta, "song", song);
if (SHOUTERR_SUCCESS != shout_set_metadata(sd->shout_conn, if (SHOUTERR_SUCCESS != shout_set_metadata(sd->shout_conn,
@ -474,26 +419,15 @@ static bool
my_shout_play(void *data, const char *chunk, size_t size) my_shout_play(void *data, const char *chunk, size_t size)
{ {
struct shout_data *sd = (struct shout_data *)data; struct shout_data *sd = (struct shout_data *)data;
int status;
if (!sd->timer->started) if (!sd->timer->started)
timer_start(sd->timer); timer_start(sd->timer);
timer_add(sd->timer, size); timer_add(sd->timer, size);
if (sd->opened && sd->tag != NULL) if (sd->tag != NULL)
send_metadata(sd); send_metadata(sd);
if (!sd->opened) {
status = open_shout_conn(sd);
if (status < 0) {
return false;
} else if (status > 0) {
timer_sync(sd->timer);
return true;
}
}
if (sd->encoder->encode_func(sd, chunk, size)) if (sd->encoder->encode_func(sd, chunk, size))
return false; return false;

View File

@ -68,13 +68,9 @@ struct shout_data {
float quality; float quality;
int bitrate; int bitrate;
bool opened;
struct tag *tag; struct tag *tag;
int timeout; int timeout;
int conn_attempts;
time_t last_attempt;
Timer *timer; Timer *timer;