diff options
Diffstat (limited to 'src/audioOutputs/audioOutput_shout.c')
-rw-r--r-- | src/audioOutputs/audioOutput_shout.c | 596 |
1 files changed, 0 insertions, 596 deletions
diff --git a/src/audioOutputs/audioOutput_shout.c b/src/audioOutputs/audioOutput_shout.c deleted file mode 100644 index ae31b07ea..000000000 --- a/src/audioOutputs/audioOutput_shout.c +++ /dev/null @@ -1,596 +0,0 @@ -/* the Music Player Daemon (MPD) - * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com) - * This project's homepage is: http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "audioOutput_shout.h" - -#ifdef HAVE_SHOUT - -#include "../utils.h" - -#include <assert.h> - -#define CONN_ATTEMPT_INTERVAL 60 -#define DEFAULT_CONN_TIMEOUT 2 - -static int shout_init_count; - -static const struct shout_encoder_plugin *const shout_encoder_plugins[] = { -#ifdef HAVE_SHOUT_MP3 - &shout_mp3_encoder, -#endif -#ifdef HAVE_SHOUT_OGG - &shout_ogg_encoder, -#endif - NULL -}; - -static const struct shout_encoder_plugin * -shout_encoder_plugin_get(const char *name) -{ - unsigned i; - - for (i = 0; shout_encoder_plugins[i] != NULL; ++i) - if (strcmp(shout_encoder_plugins[i]->name, name) == 0) - return shout_encoder_plugins[i]; - - return NULL; -} - -static struct shout_data *new_shout_data(void) -{ - struct shout_data *ret = xmalloc(sizeof(*ret)); - - ret->shout_conn = shout_new(); - ret->shout_meta = shout_metadata_new(); - ret->opened = 0; - ret->tag = NULL; - ret->tag_to_send = 0; - ret->bitrate = -1; - ret->quality = -2.0; - ret->timeout = DEFAULT_CONN_TIMEOUT; - ret->conn_attempts = 0; - ret->last_attempt = 0; - ret->timer = NULL; - ret->buf.len = 0; - - return ret; -} - -static void free_shout_data(struct shout_data *sd) -{ - if (sd->shout_meta) - shout_metadata_free(sd->shout_meta); - if (sd->shout_conn) - shout_free(sd->shout_conn); - if (sd->tag) - tag_free(sd->tag); - if (sd->timer) - timer_free(sd->timer); - - free(sd); -} - -#define check_block_param(name) { \ - block_param = getBlockParam(param, name); \ - if (!block_param) { \ - FATAL("no \"%s\" defined for shout device defined at line " \ - "%i\n", name, param->line); \ - } \ - } - -static void *my_shout_init_driver(struct audio_output *audio_output, - const struct audio_format *audio_format, - ConfigParam *param) -{ - struct shout_data *sd; - char *test; - int port; - char *host; - char *mount; - char *passwd; - const char *encoding; - unsigned protocol; - const char *user; - char *name; - BlockParam *block_param; - int public; - - sd = new_shout_data(); - sd->audio_output = audio_output; - - if (shout_init_count == 0) - shout_init(); - - shout_init_count++; - - check_block_param("host"); - host = block_param->value; - - check_block_param("mount"); - mount = block_param->value; - - check_block_param("port"); - - port = strtol(block_param->value, &test, 10); - - if (*test != '\0' || port <= 0) { - FATAL("shout port \"%s\" is not a positive integer, line %i\n", - block_param->value, block_param->line); - } - - check_block_param("password"); - passwd = block_param->value; - - check_block_param("name"); - name = block_param->value; - - public = getBoolBlockParam(param, "public", 1); - if (public == CONF_BOOL_UNSET) - public = 0; - - block_param = getBlockParam(param, "user"); - if (block_param) - user = block_param->value; - else - user = "source"; - - block_param = getBlockParam(param, "quality"); - - if (block_param) { - int line = block_param->line; - - sd->quality = strtod(block_param->value, &test); - - if (*test != '\0' || sd->quality < -1.0 || sd->quality > 10.0) { - FATAL("shout quality \"%s\" is not a number in the " - "range -1 to 10, line %i\n", block_param->value, - block_param->line); - } - - block_param = getBlockParam(param, "bitrate"); - - if (block_param) { - FATAL("quality (line %i) and bitrate (line %i) are " - "both defined for shout output\n", line, - block_param->line); - } - } else { - block_param = getBlockParam(param, "bitrate"); - - if (!block_param) { - FATAL("neither bitrate nor quality defined for shout " - "output at line %i\n", param->line); - } - - sd->bitrate = strtol(block_param->value, &test, 10); - - if (*test != '\0' || sd->bitrate <= 0) { - FATAL("bitrate at line %i should be a positive integer " - "\n", block_param->line); - } - } - - check_block_param("format"); - - assert(audio_format != NULL); - sd->audio_format = *audio_format; - - block_param = getBlockParam(param, "encoding"); - if (block_param) { - if (0 == strcmp(block_param->value, "mp3")) - encoding = block_param->value; - else if (0 == strcmp(block_param->value, "ogg")) - encoding = block_param->value; - else - FATAL("shout encoding \"%s\" is not \"ogg\" or " - "\"mp3\", line %i\n", block_param->value, - block_param->line); - } else { - encoding = "ogg"; - } - - sd->encoder = shout_encoder_plugin_get(encoding); - if (sd->encoder == NULL) - FATAL("couldn't find shout encoder plugin for \"%s\" " - "at line %i\n", encoding, block_param->line); - - check_block_param("protocol"); - - block_param = getBlockParam(param, "protocol"); - if (block_param) { - if (0 == strcmp(block_param->value, "shoutcast") && - 0 != strcmp(encoding, "mp3")) - FATAL("you cannot stream \"%s\" to shoutcast, use mp3\n", - encoding); - else if (0 == strcmp(block_param->value, "shoutcast")) - protocol = SHOUT_PROTOCOL_ICY; - else if (0 == strcmp(block_param->value, "icecast1")) - protocol = SHOUT_PROTOCOL_XAUDIOCAST; - else if (0 == strcmp(block_param->value, "icecast2")) - protocol = SHOUT_PROTOCOL_HTTP; - else - FATAL("shout protocol \"%s\" is not \"shoutcast\" or " - "\"icecast1\"or " - "\"icecast2\", line %i\n", block_param->value, - block_param->line); - } else { - protocol = SHOUT_PROTOCOL_HTTP; - } - - if (shout_set_host(sd->shout_conn, host) != SHOUTERR_SUCCESS || - shout_set_port(sd->shout_conn, port) != SHOUTERR_SUCCESS || - shout_set_password(sd->shout_conn, passwd) != SHOUTERR_SUCCESS || - shout_set_mount(sd->shout_conn, mount) != SHOUTERR_SUCCESS || - shout_set_name(sd->shout_conn, name) != SHOUTERR_SUCCESS || - shout_set_user(sd->shout_conn, user) != 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) - != SHOUTERR_SUCCESS || - shout_set_protocol(sd->shout_conn, protocol) != SHOUTERR_SUCCESS || - shout_set_agent(sd->shout_conn, "MPD") != SHOUTERR_SUCCESS) { - FATAL("error configuring shout defined at line %i: %s\n", - param->line, shout_get_error(sd->shout_conn)); - } - - /* optional paramters */ - block_param = getBlockParam(param, "timeout"); - if (block_param) { - sd->timeout = (int)strtol(block_param->value, &test, 10); - if (*test != '\0' || sd->timeout <= 0) { - FATAL("shout timeout is not a positive integer, " - "line %i\n", block_param->line); - } - } - - block_param = getBlockParam(param, "genre"); - if (block_param && shout_set_genre(sd->shout_conn, block_param->value)) { - FATAL("error configuring shout defined at line %i: %s\n", - param->line, shout_get_error(sd->shout_conn)); - } - - block_param = getBlockParam(param, "description"); - if (block_param && shout_set_description(sd->shout_conn, - block_param->value)) { - FATAL("error configuring shout defined at line %i: %s\n", - param->line, shout_get_error(sd->shout_conn)); - } - - { - char temp[11]; - memset(temp, 0, sizeof(temp)); - - snprintf(temp, sizeof(temp), "%u", sd->audio_format.channels); - shout_set_audio_info(sd->shout_conn, SHOUT_AI_CHANNELS, temp); - - snprintf(temp, sizeof(temp), "%u", sd->audio_format.sample_rate); - - shout_set_audio_info(sd->shout_conn, SHOUT_AI_SAMPLERATE, temp); - - if (sd->quality >= -1.0) { - snprintf(temp, sizeof(temp), "%2.2f", sd->quality); - shout_set_audio_info(sd->shout_conn, SHOUT_AI_QUALITY, - temp); - } else { - snprintf(temp, sizeof(temp), "%d", sd->bitrate); - shout_set_audio_info(sd->shout_conn, SHOUT_AI_BITRATE, - temp); - } - } - - if (sd->encoder->init_func(sd) != 0) - FATAL("shout: encoder plugin '%s' failed to initialize\n", - sd->encoder->name); - - return sd; -} - -static int handle_shout_error(struct shout_data *sd, int err) -{ - switch (err) { - case SHOUTERR_SUCCESS: - break; - case SHOUTERR_UNCONNECTED: - case SHOUTERR_SOCKET: - ERROR("Lost shout connection to %s:%i: %s\n", - shout_get_host(sd->shout_conn), - shout_get_port(sd->shout_conn), - shout_get_error(sd->shout_conn)); - sd->shout_error = 1; - return -1; - default: - ERROR("shout: connection to %s:%i error: %s\n", - shout_get_host(sd->shout_conn), - shout_get_port(sd->shout_conn), - shout_get_error(sd->shout_conn)); - sd->shout_error = 1; - return -1; - } - - return 0; -} - -static int write_page(struct shout_data *sd) -{ - int err; - - if (sd->buf.len == 0) - return 0; - - shout_sync(sd->shout_conn); - err = shout_send(sd->shout_conn, sd->buf.data, sd->buf.len); - if (handle_shout_error(sd, err) < 0) - return -1; - sd->buf.len = 0; - - return 0; -} - -static void close_shout_conn(struct shout_data * sd) -{ - if (sd->opened) { - if (sd->encoder->clear_encoder_func(sd)) - write_page(sd); - } - - if (shout_get_connected(sd->shout_conn) != SHOUTERR_UNCONNECTED && - shout_close(sd->shout_conn) != SHOUTERR_SUCCESS) { - ERROR("problem closing connection to shout server: %s\n", - shout_get_error(sd->shout_conn)); - } - - sd->opened = 0; -} - -static void my_shout_finish_driver(void *data) -{ - struct shout_data *sd = (struct shout_data *)data; - - close_shout_conn(sd); - - sd->encoder->finish_func(sd); - free_shout_data(sd); - - shout_init_count--; - - if (shout_init_count == 0) - shout_shutdown(); -} - -static void my_shout_drop_buffered_audio(void *data) -{ - struct shout_data *sd = (struct shout_data *)data; - timer_reset(sd->timer); - - /* needs to be implemented for shout */ -} - -static void my_shout_close_device(void *data) -{ - struct shout_data *sd = (struct shout_data *)data; - - close_shout_conn(sd); - - if (sd->timer) { - timer_free(sd->timer); - sd->timer = NULL; - } -} - -static int shout_connect(struct shout_data *sd) -{ - time_t t = time(NULL); - 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) { - ERROR("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); - switch (state) { - case SHOUTERR_SUCCESS: - case SHOUTERR_CONNECTED: - return 0; - case SHOUTERR_BUSY: - return 1; - default: - ERROR("problem opening connection to shout server %s:%i " - "(attempt %i): %s\n", - shout_get_host(sd->shout_conn), - shout_get_port(sd->shout_conn), - sd->conn_attempts, shout_get_error(sd->shout_conn)); - return -1; - } -} - -static int open_shout_conn(void *data) -{ - struct shout_data *sd = (struct shout_data *)data; - int status; - - status = shout_connect(sd); - if (status != 0) - return status; - - if (sd->encoder->init_encoder_func(sd) < 0) { - shout_close(sd->shout_conn); - return -1; - } - - write_page(sd); - - sd->shout_error = 0; - sd->opened = 1; - sd->tag_to_send = 1; - sd->conn_attempts = 0; - - return 0; -} - -static int my_shout_open_device(void *data, - struct audio_format *audio_format) -{ - struct shout_data *sd = (struct shout_data *)data; - - if (!sd->opened && open_shout_conn(sd) < 0) - return -1; - - if (sd->timer) - timer_free(sd->timer); - - sd->timer = timer_new(audio_format); - - return 0; -} - -static void send_metadata(struct shout_data * sd) -{ - static const int size = 1024; - char song[size]; - - if (!sd->opened || !sd->tag) - return; - - if (sd->encoder->send_metadata_func(sd, song, size)) { - shout_metadata_add(sd->shout_meta, "song", song); - if (SHOUTERR_SUCCESS != shout_set_metadata(sd->shout_conn, - sd->shout_meta)) { - ERROR("error setting shout metadata\n"); - return; - } - } - - sd->tag_to_send = 0; -} - -static int my_shout_play(void *data, - const char *chunk, size_t size) -{ - struct shout_data *sd = (struct shout_data *)data; - int status; - - if (!sd->timer->started) - timer_start(sd->timer); - - timer_add(sd->timer, size); - - if (sd->opened && sd->tag_to_send) - send_metadata(sd); - - if (!sd->opened) { - status = open_shout_conn(sd); - if (status < 0) { - my_shout_close_device(sd); - return -1; - } else if (status > 0) { - timer_sync(sd->timer); - return 0; - } - } - - if (sd->encoder->encode_func(sd, chunk, size)) { - my_shout_close_device(sd); - return -1; - } - - if (write_page(sd) < 0) { - my_shout_close_device(sd); - return -1; - } - - return 0; -} - -static void my_shout_pause(void *data) -{ - struct shout_data *sd = (struct shout_data *)data; - static const char silence[1020]; - int ret; - - /* play silence until the player thread sends us a command */ - - while (sd->opened && !audio_output_is_pending(sd->audio_output)) { - ret = my_shout_play(data, silence, sizeof(silence)); - if (ret != 0) - break; - } -} - -static void my_shout_set_tag(void *data, - const struct tag *tag) -{ - struct shout_data *sd = (struct shout_data *)data; - - if (sd->tag) - tag_free(sd->tag); - sd->tag = NULL; - sd->tag_to_send = 0; - - if (!tag) - return; - - sd->tag = tag_dup(tag); - sd->tag_to_send = 1; -} - -const struct audio_output_plugin shoutPlugin = { - .name = "shout", - .init = my_shout_init_driver, - .finish = my_shout_finish_driver, - .open = my_shout_open_device, - .play = my_shout_play, - .pause = my_shout_pause, - .cancel = my_shout_drop_buffered_audio, - .close = my_shout_close_device, - .send_tag = my_shout_set_tag, -}; - -#else - -DISABLED_AUDIO_OUTPUT_PLUGIN(shoutPlugin) -#endif |