Thanks for the report. I'll try to repro this and get it fixed ASAP. e. On Aug 26, 2008, at 3:39 AM, Qball Cow wrote:
> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > I tried the patch, and I ran in the following problem: > When I enable the output "on the fly", mpd (sometimes) starts > outputting > this: > * strange error flushing buffer ... > > On occasion mpd crashes with a floating point exception. (only with > mp3 > output enabled). > > Q > > > Eric Wollesen wrote: >> Configuration options for "shout_mp3" are the same as for "shout". >> --- >> configure.ac | 33 ++ >> m4/lame.m4 | 108 +++++ >> src/Makefile.am | 1 + >> src/audio.c | 1 + >> src/audioOutput.h | 1 + >> src/audioOutputs/audioOutput_shout_mp3.c | 676 ++++++++++++++++++++ >> ++++++++++ >> 6 files changed, 820 insertions(+), 0 deletions(-) >> create mode 100644 m4/lame.m4 >> create mode 100644 src/audioOutputs/audioOutput_shout_mp3.c >> >> diff --git a/configure.ac b/configure.ac >> index 6067bc4..f7ecc6c 100644 >> --- a/configure.ac >> +++ b/configure.ac >> @@ -71,6 +71,8 @@ fi >> >> AC_ARG_ENABLE(ao,[ --enable-ao enable support for >> libao (default: disable)],[enable_ao=$enableval],[enable_ao=no]) >> AC_ARG_ENABLE(shout,[ --disable-shout disable support for >> streaming through shout (default: enable)],[enable_shout= >> $enableval],[enable_shout=yes]) >> +AC_ARG_ENABLE(shout_mp3,[ --disable-shout_mp3 disable >> support for mp3 >> +streaming through shout (default: enable)],[enable_shout_mp3= >> $enableval],[enable_shout_mp3=yes]) >> AC_ARG_ENABLE(iconv,[ --disable-iconv disable iconv >> support (default: enable)],[enable_iconv=$enableval], >> [enable_iconv=yes]) >> AC_ARG_ENABLE(ipv6,[ --disable-ipv6 disable IPv6 support >> (default: enable)],[enable_ipv6=$enableval],[enable_ipv6=yes]) >> AC_ARG_ENABLE(tcp,[ --disable-tcp disable support for >> clients connecting via TCP (default: enable)],[enable_tcp= >> $enableval],[enable_tcp=yes]) >> @@ -85,6 +87,7 @@ AC_ARG_ENABLE(oggvorbis,[ --disable- >> oggvorbis disable Ogg Vorbis support (d >> AC_ARG_ENABLE(oggflac,[ --disable-oggflac disable OggFLAC >> support (default: enable)],[enable_oggflac= >> $enableval],enable_oggflac=yes) >> AC_ARG_ENABLE(flac,[ --disable-flac disable flac support >> (default: enable)],[enable_flac=$enableval],[enable_flac=yes]) >> AC_ARG_ENABLE(mp3,[ --disable-mp3 disable mp3 support >> (default: enable)],[enable_mp3=$enableval],[enable_mp3=yes]) >> +AC_ARG_ENABLE(lame,[ --disable-lame disable lame >> support (default: enable)],[enable_lame=$enableval], >> [enable_lame=yes]) >> AC_ARG_ENABLE(aac,[ --disable-aac disable AAC support >> (default: enable)],[enable_aac=$enableval],[enable_aac=yes]) >> AC_ARG_ENABLE(audiofile,[ --disable-audiofile disable >> audiofile support, disables wave support (default: enable)], >> [enable_audiofile=$enableval],[enable_audiofile=yes]) >> AC_ARG_ENABLE(mod,[ --enable-mod enable MOD support >> (default: disable)],[enable_mod=$enableval],[enable_mod=yes]) >> @@ -193,6 +196,13 @@ if test x$enable_shout = xyes; then >> fi >> fi >> >> +if test x$enable_shout_mp3 = xyes; then >> + if test x$enable_lame = xno; then >> + AC_MSG_WARN([disabling shout_mp3 streaming support >> because lame is not enabled]) >> + enable_shout_mp3=no >> + fi >> +fi >> + >> if test x$enable_ao = xyes; then >> XIPH_PATH_AO([AC_DEFINE(HAVE_AO, 1, [Define to play with ao]) >> MPD_LIBS="$MPD_LIBS $AO_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AO_CFLAGS"], >> enable_ao=no) >> fi >> @@ -201,6 +211,10 @@ if test x$enable_shout = xyes; then >> XIPH_PATH_SHOUT([AC_DEFINE(HAVE_SHOUT, 1, [Define to enable >> libshout support]) MPD_LIBS="$MPD_LIBS $SHOUT_LIBS" >> MPD_CFLAGS="$MPD_CFLAGS $SHOUT_CFLAGS"], enable_shout=no) >> fi >> >> +if test x$enable_shout_mp3 = xyes; then >> + XIPH_PATH_SHOUT([AC_DEFINE(HAVE_SHOUT_MP3, 1, [Define to >> enable mp3 libshout support]) MPD_LIBS="$MPD_LIBS $SHOUT_LIBS" >> MPD_CFLAGS="$MPD_CFLAGS $SHOUT_CFLAGS"], enable_shout_mp3=no) >> +fi >> + >> if test x$enable_oss = xyes; then >> AC_CHECK_HEADER(sys/soundcard.h,[enable_oss=yes;AC_DEFINE(HAVE_OSS, >> 1,[Define to enable OSS])],[AC_MSG_WARN(Soundcard headers not found >> -- disabling OSS support);enable_oss=no]) >> fi >> @@ -354,6 +368,12 @@ if test x$enable_mp3 = xyes; then >> fi >> fi >> >> +if test x$enable_lame = xyes; then >> + AM_PATH_LAME([MPD_LIBS="$MPD_LIBS $LAME_LIBS" >> MPD_CFLAGS="$MPD_CFLAGS $LAME_CFLAGS"], >> + [enable_lame=no;AC_MSG_WARN(You need lame -- >> disabling lame support)]) >> +fi >> + >> + >> if test x$enable_mpc = xyes; then >> if test "x$mpcdec_libraries" != "x" ; then >> MPCDEC_LIBS="-L$mpcdec_libraries" >> @@ -743,11 +763,18 @@ else >> echo " Shout streaming support .......disabled" >> fi >> >> +if test x$enable_shout_mp3 = xyes; then >> + echo " Shout mp3 streaming support ...enabled" >> +else >> + echo " Shout mp3 streaming support ...disabled" >> +fi >> + >> echo "" >> >> if test x$enable_ao = xno && >> test x$enable_oss = xno && >> test x$enable_shout = xno && >> + test x$enable_shout_mp3 = xno && >> test x$enable_alsa = xno && >> test x$enable_osx = xno && >> test x$enable_pulse = xno && >> @@ -771,6 +798,12 @@ else >> echo " mp3 support ...................disabled" >> fi >> >> +if test x$enable_lame = xyes; then >> + echo " lame support ..................enabled" >> +else >> + echo " lame support ..................disabled" >> +fi >> + >> if test x$enable_oggvorbis = xyes; then >> echo " Ogg Vorbis support ............enabled" >> if test x$use_tremor = xyes; then >> diff --git a/m4/lame.m4 b/m4/lame.m4 >> new file mode 100644 >> index 0000000..5ebf550 >> --- /dev/null >> +++ b/m4/lame.m4 >> @@ -0,0 +1,108 @@ >> +dnl borrowed from oddsock.org >> +dnl AM_PATH_LAME([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) >> +dnl Test for liblame, and define LAME_CFLAGS and LAME_LIBS >> +dnl >> +AC_DEFUN([AM_PATH_LAME], >> +[dnl >> +dnl Get the cflags and libraries >> +dnl >> +AC_ARG_WITH(lame,[ --with-lame=PFX Prefix where liblame is >> installed (optional)], lame_prefix="$withval", lame_prefix="") >> +AC_ARG_WITH(lame-libraries,[ --with-lame-libraries=DIR >> Directory where liblame library is installed (optional)], >> lame_libraries="$withval", lame_libraries="") >> +AC_ARG_WITH(lame-includes,[ --with-lame-includes=DIR Directory >> where liblame header files are installed (optional)], >> lame_includes="$withval", lame_includes="") >> +AC_ARG_ENABLE(lametest, [ --disable-lametest Do not try to >> compile and run a test liblame program],, enable_lametest=yes) >> + >> +if test "x$lame_prefix" != "xno" ; then >> + >> + if test "x$lame_libraries" != "x" ; then >> + LAME_LIBS="-L$lame_libraries" >> + elif test "x$lame_prefix" != "x" ; then >> + LAME_LIBS="-L$lame_prefix/lib" >> + elif test "x$prefix" != "xNONE" ; then >> + LAME_LIBS="-L$prefix/lib" >> + fi >> + >> + LAME_LIBS="$LAME_LIBS -lmp3lame -lm" >> + >> + if test "x$lame_includes" != "x" ; then >> + LAME_CFLAGS="-I$lame_includes" >> + elif test "x$lame_prefix" != "x" ; then >> + LAME_CFLAGS="-I$lame_prefix/include" >> + elif test "x$prefix" != "xNONE"; then >> + LAME_CFLAGS="-I$prefix/include" >> + fi >> + >> + AC_MSG_CHECKING(for liblame) >> + no_lame="" >> + >> + >> + if test "x$enable_lametest" = "xyes" ; then >> + ac_save_CFLAGS="$CFLAGS" >> + ac_save_LIBS="$LIBS" >> + CFLAGS="$CFLAGS $LAME_CFLAGS" >> + LIBS="$LIBS $LAME_LIBS" >> +dnl >> +dnl Now check if the installed liblame is sufficiently new. >> +dnl >> + rm -f conf.lametest >> + AC_TRY_RUN([ >> +#include <stdio.h> >> +#include <stdlib.h> >> +#include <string.h> >> +#include <lame/lame.h> >> + >> +int main () >> +{ >> + system("touch conf.lametest"); >> + return 0; >> +} >> + >> +],, no_lame=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) >> + CFLAGS="$ac_save_CFLAGS" >> + LIBS="$ac_save_LIBS" >> + fi >> + >> + if test "x$no_lame" = "x" ; then >> + AC_MSG_RESULT(yes) >> + ifelse([$1], , :, [$1]) >> + else >> + AC_MSG_RESULT(no) >> + if test -f conf.lametest ; then >> + : >> + else >> + echo "*** Could not run liblame test program, checking >> why..." >> + CFLAGS="$CFLAGS $LAME_CFLAGS" >> + LIBS="$LIBS $LAME_LIBS" >> + AC_TRY_LINK([ >> +#include <stdio.h> >> +#include <lame/lame.h> >> +], [ return 0; ], >> + [ echo "*** The test program compiled, but did not run. >> This usually means" >> + echo "*** that the run-time linker is not finding liblame >> or finding the wrong" >> + echo "*** version of liblame. If it is not finding liblame, >> you'll need to set your" >> + echo "*** LD_LIBRARY_PATH environment variable, or edit / >> etc/ld.so.conf to point" >> + echo "*** to the installed location Also, make sure you >> have run ldconfig if that" >> + echo "*** is required on your system" >> + echo "***" >> + echo "*** If you have an old version installed, it is best >> to remove it, although" >> + echo "*** you may also be able to get things to work by >> modifying LD_LIBRARY_PATH"], >> + [ echo "*** The test program failed to compile or link. See >> the file config.log for the" >> + echo "*** exact error that occured. This usually means >> liblame was incorrectly installed" >> + echo "*** or that you have moved liblame since it was >> installed." ]) >> + CFLAGS="$ac_save_CFLAGS" >> + LIBS="$ac_save_LIBS" >> + fi >> + LAME_CFLAGS="" >> + LAME_LIBS="" >> + ifelse([$2], , :, [$2]) >> + fi >> + AC_DEFINE(HAVE_LAME, 1, [Define if you have liblame.]) >> + use_lame="1" >> +else >> + LAME_CFLAGS="" >> + LAME_LIBS="" >> +fi >> + AC_SUBST(LAME_CFLAGS) >> + AC_SUBST(LAME_LIBS) >> + rm -f conf.lametest >> +]) >> + >> diff --git a/src/Makefile.am b/src/Makefile.am >> index 6c52dde..512e84e 100644 >> --- a/src/Makefile.am >> +++ b/src/Makefile.am >> @@ -3,6 +3,7 @@ SUBDIRS = $(MP4FF_SUBDIR) >> >> mpd_audioOutputs = \ >> audioOutputs/audioOutput_shout.c \ >> + audioOutputs/audioOutput_shout_mp3.c \ >> audioOutputs/audioOutput_null.c \ >> audioOutputs/audioOutput_fifo.c \ >> audioOutputs/audioOutput_alsa.c \ >> diff --git a/src/audio.c b/src/audio.c >> index 34b74e6..3334ff0 100644 >> --- a/src/audio.c >> +++ b/src/audio.c >> @@ -85,6 +85,7 @@ void loadAudioDrivers(void) >> { >> initAudioOutputPlugins(); >> loadAudioOutputPlugin(&shoutPlugin); >> + loadAudioOutputPlugin(&shoutMp3Plugin); >> loadAudioOutputPlugin(&nullPlugin); >> loadAudioOutputPlugin(&fifoPlugin); >> loadAudioOutputPlugin(&alsaPlugin); >> diff --git a/src/audioOutput.h b/src/audioOutput.h >> index 7574f5a..b98334e 100644 >> --- a/src/audioOutput.h >> +++ b/src/audioOutput.h >> @@ -109,6 +109,7 @@ void sendMetadataToAudioOutput(AudioOutput * >> audioOutput, MpdTag * tag); >> void printAllOutputPluginTypes(FILE * fp); >> >> extern AudioOutputPlugin shoutPlugin; >> +extern AudioOutputPlugin shoutMp3Plugin; >> extern AudioOutputPlugin nullPlugin; >> extern AudioOutputPlugin fifoPlugin; >> extern AudioOutputPlugin alsaPlugin; >> diff --git a/src/audioOutputs/audioOutput_shout_mp3.c b/src/ >> audioOutputs/audioOutput_shout_mp3.c >> new file mode 100644 >> index 0000000..da76a21 >> --- /dev/null >> +++ b/src/audioOutputs/audioOutput_shout_mp3.c >> @@ -0,0 +1,676 @@ >> +/* the Music Player Daemon (MPD) >> + * Copyright (C) 2003-2007 by Warren Dukes ([EMAIL PROTECTED]) >> + * 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.h" >> + >> +#ifdef HAVE_SHOUT_MP3 >> + >> +#include "../conf.h" >> +#include "../log.h" >> +#include "../pcm_utils.h" >> +#include "../timer.h" >> + >> +#include <shout/shout.h> >> +#include <lame/lame.h> >> + >> +#define CONN_ATTEMPT_INTERVAL 60 >> +#define DEFAULT_CONN_TIMEOUT 2 >> +#define MP3_BUF_SIZE 1048576 >> + >> +static int shoutInitCount; >> + >> +/* lots of this code blatantly stolent from bossogg/bossao2 */ >> + >> +typedef struct _ShoutData { >> + shout_t *shoutConn; >> + int shoutError; >> + shout_metadata_t *shoutMeta; >> + >> + lame_global_flags *gfp; >> + unsigned char mp3buf[MP3_BUF_SIZE]; >> + unsigned int mp3buf_full; >> + >> + float quality; >> + int bitrate; >> + >> + int opened; >> + >> + MpdTag *tag; >> + int tagToSend; >> + >> + int timeout; >> + int connAttempts; >> + time_t lastAttempt; >> + >> + Timer *timer; >> + >> + /* just a pointer to audioOutput->outAudioFormat */ >> + AudioFormat *audioFormat; >> +} ShoutData; >> + >> +static ShoutData *newShoutData(void) >> +{ >> + ShoutData *ret = xmalloc(sizeof(ShoutData)); >> + >> + ret->shoutConn = shout_new(); >> + ret->shoutMeta = shout_metadata_new(); >> + ret->opened = 0; >> + ret->tag = NULL; >> + ret->tagToSend = 0; >> + ret->bitrate = -1; >> + ret->quality = -2.0; >> + ret->timeout = DEFAULT_CONN_TIMEOUT; >> + ret->connAttempts = 0; >> + ret->lastAttempt = 0; >> + ret->audioFormat = NULL; >> + ret->timer = NULL; >> + >> + return ret; >> +} >> + >> +static void freeShoutData(ShoutData * sd) >> +{ >> + if (sd->shoutMeta) >> + shout_metadata_free(sd->shoutMeta); >> + if (sd->shoutConn) >> + shout_free(sd->shoutConn); >> + if (sd->tag) >> + freeMpdTag(sd->tag); >> + if (sd->timer) >> + timer_free(sd->timer); >> + >> + free(sd); >> +} >> + >> +#define checkBlockParam(name) { \ >> + blockParam = getBlockParam(param, name); \ >> + if (!blockParam) { \ >> + FATAL("no \"%s\" defined for shout_mp3 device >> defined at line " \ >> + "%i\n", name, param->line); \ >> + } \ >> +} >> + >> +static int myShoutMp3_initDriver(AudioOutput * audioOutput, >> + ConfigParam * param) >> +{ >> + ShoutData *sd; >> + char *test; >> + int port; >> + char *host; >> + char *mount; >> + char *passwd; >> + const char *user; >> + char *name; >> + BlockParam *blockParam; >> + int public; >> + >> + sd = newShoutData(); >> + >> + if (shoutInitCount == 0) >> + shout_init(); >> + >> + shoutInitCount++; >> + >> + checkBlockParam("host"); >> + host = blockParam->value; >> + >> + checkBlockParam("mount"); >> + mount = blockParam->value; >> + >> + checkBlockParam("port"); >> + >> + port = strtol(blockParam->value, &test, 10); >> + >> + if (*test != '\0' || port <= 0) { >> + FATAL("shout port \"%s\" is not a positive >> integer, line %i\n", >> + blockParam->value, blockParam->line); >> + } >> + >> + checkBlockParam("password"); >> + passwd = blockParam->value; >> + >> + checkBlockParam("name"); >> + name = blockParam->value; >> + >> + public = getBoolBlockParam(param, "public", 1); >> + if (public == CONF_BOOL_UNSET) >> + public = 0; >> + >> + blockParam = getBlockParam(param, "user"); >> + if (blockParam) >> + user = blockParam->value; >> + else >> + user = "source"; >> + >> + blockParam = getBlockParam(param, "quality"); >> + >> + if (blockParam) { >> + int line = blockParam->line; >> + >> + sd->quality = strtod(blockParam->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", >> blockParam->value, >> + blockParam->line); >> + } >> + >> + blockParam = getBlockParam(param, "bitrate"); >> + >> + if (blockParam) { >> + FATAL("quality (line %i) and bitrate (line >> %i) are " >> + "both defined for shout_mp3 output >> \n", line, >> + blockParam->line); >> + } >> + } else { >> + blockParam = getBlockParam(param, "bitrate"); >> + >> + if (!blockParam) { >> + FATAL("neither bitrate nor quality defined >> for shout_mp3 " >> + "output at line %i\n", param->line); >> + } >> + >> + sd->bitrate = strtol(blockParam->value, &test, 10); >> + >> + if (*test != '\0' || sd->bitrate <= 0) { >> + FATAL("bitrate at line %i should be a >> positive integer " >> + "\n", blockParam->line); >> + } >> + } >> + >> + checkBlockParam("format"); >> + sd->audioFormat = &audioOutput->outAudioFormat; >> + >> + if (shout_set_host(sd->shoutConn, host) != >> SHOUTERR_SUCCESS || >> + shout_set_port(sd->shoutConn, port) != >> SHOUTERR_SUCCESS || >> + shout_set_password(sd->shoutConn, passwd) != >> SHOUTERR_SUCCESS || >> + shout_set_mount(sd->shoutConn, mount) != >> SHOUTERR_SUCCESS || >> + shout_set_name(sd->shoutConn, name) != >> SHOUTERR_SUCCESS || >> + shout_set_user(sd->shoutConn, user) != >> SHOUTERR_SUCCESS || >> + shout_set_public(sd->shoutConn, public) != >> SHOUTERR_SUCCESS || >> + shout_set_nonblocking(sd->shoutConn, 1) != >> SHOUTERR_SUCCESS || >> + shout_set_format(sd->shoutConn, SHOUT_FORMAT_MP3) >> + != SHOUTERR_SUCCESS || >> + shout_set_protocol(sd->shoutConn, SHOUT_PROTOCOL_HTTP) >> + != SHOUTERR_SUCCESS || >> + shout_set_agent(sd->shoutConn, "MPD") != >> SHOUTERR_SUCCESS) { >> + FATAL("error configuring shout_mp3 defined at line >> %i: %s\n", >> + param->line, shout_get_error(sd->shoutConn)); >> + } >> + >> + /* optional paramters */ >> + blockParam = getBlockParam(param, "timeout"); >> + if (blockParam) { >> + sd->timeout = (int)strtol(blockParam->value, >> &test, 10); >> + if (*test != '\0' || sd->timeout <= 0) { >> + FATAL("shout timeout is not a positive >> integer, " >> + "line %i\n", blockParam->line); >> + } >> + } >> + >> + blockParam = getBlockParam(param, "genre"); >> + if (blockParam && shout_set_genre(sd->shoutConn, >> blockParam->value)) { >> + FATAL("error configuring shout_mp3 defined at line >> %i: %s\n", >> + param->line, shout_get_error(sd->shoutConn)); >> + } >> + >> + blockParam = getBlockParam(param, "description"); >> + if (blockParam && shout_set_description(sd->shoutConn, >> + blockParam- >> >value)) { >> + FATAL("error configuring shout_mp3 defined at line >> %i: %s\n", >> + param->line, shout_get_error(sd->shoutConn)); >> + } >> + >> + { >> + char temp[11]; >> + memset(temp, 0, sizeof(temp)); >> + >> + snprintf(temp, sizeof(temp), "%d", sd->audioFormat- >> >channels); >> + shout_set_audio_info(sd->shoutConn, >> SHOUT_AI_CHANNELS, temp); >> + >> + snprintf(temp, sizeof(temp), "%d", sd->audioFormat- >> >sampleRate); >> + >> + shout_set_audio_info(sd->shoutConn, >> SHOUT_AI_SAMPLERATE, temp); >> + >> + if (sd->quality >= -1.0) { >> + snprintf(temp, sizeof(temp), "%2.2f", sd- >> >quality); >> + shout_set_audio_info(sd->shoutConn, >> SHOUT_AI_QUALITY, >> + temp); >> + } else { >> + snprintf(temp, sizeof(temp), "%d", sd- >> >bitrate); >> + shout_set_audio_info(sd->shoutConn, >> SHOUT_AI_BITRATE, >> + temp); >> + } >> + } >> + >> + audioOutput->data = sd; >> + >> + return 0; >> +} >> + >> +static int myShoutMp3_handleError(ShoutData * sd, int err) >> +{ >> + switch (err) { >> + case SHOUTERR_SUCCESS: >> + break; >> + case SHOUTERR_UNCONNECTED: >> + case SHOUTERR_SOCKET: >> + ERROR("Lost shout_mp3 connection to %s:%i: %s\n", >> + shout_get_host(sd->shoutConn), >> + shout_get_port(sd->shoutConn), >> + shout_get_error(sd->shoutConn)); >> + sd->shoutError = 1; >> + return -1; >> + default: >> + ERROR("shout_mp3: connection to %s:%i error: %s\n", >> + shout_get_host(sd->shoutConn), >> + shout_get_port(sd->shoutConn), >> + shout_get_error(sd->shoutConn)); >> + sd->shoutError = 1; >> + return -1; >> + } >> + >> + return 0; >> +} >> + >> +static int write_page(ShoutData * sd) >> +{ >> + int err; >> + >> + shout_sync(sd->shoutConn); >> + err = shout_send(sd->shoutConn, sd->mp3buf, sd- >> >mp3buf_full); >> + if (myShoutMp3_handleError(sd, err) < 0) >> + return -1; >> + >> + return 0; >> +} >> + >> +static void finishEncoder(ShoutData * sd) >> +{ >> + /* Does lame require anything to be done here? */ >> +} >> + >> +static int flushEncoder(ShoutData * sd) >> +{ >> + /* Does lame require anything to be done here? */ >> + return 0; >> +} >> + >> +static void clearEncoder(ShoutData * sd) >> +{ >> + finishEncoder(sd); >> + while (1 == flushEncoder(sd)) { >> + if (!sd->shoutError) >> + write_page(sd); >> + } >> + >> + lame_close(sd->gfp); >> +} >> + >> +static void myShoutMp3_closeShoutConn(ShoutData * sd) >> +{ >> + if (sd->opened) >> + clearEncoder(sd); >> + >> + if (shout_get_connected(sd->shoutConn) != >> SHOUTERR_UNCONNECTED && >> + shout_close(sd->shoutConn) != SHOUTERR_SUCCESS) { >> + ERROR("problem closing connection to shout_mp3 >> server: %s\n", >> + shout_get_error(sd->shoutConn)); >> + } >> + >> + sd->opened = 0; >> +} >> + >> +static void myShoutMp3_finishDriver(AudioOutput * audioOutput) >> +{ >> + ShoutData *sd = (ShoutData *) audioOutput->data; >> + >> + myShoutMp3_closeShoutConn(sd); >> + >> + freeShoutData(sd); >> + >> + shoutInitCount--; >> + >> + if (shoutInitCount == 0) >> + shout_shutdown(); >> +} >> + >> +static void myShoutMp3_dropBufferedAudio(AudioOutput * audioOutput) >> +{ >> + ShoutData *sd = (ShoutData *)audioOutput->data; >> + timer_reset(sd->timer); >> + >> + /* needs to be implemented for shout_mp3 */ >> +} >> + >> +static void myShoutMp3_closeDevice(AudioOutput * audioOutput) >> +{ >> + ShoutData *sd = (ShoutData *) audioOutput->data; >> + >> + myShoutMp3_closeShoutConn(sd); >> + >> + if (sd->timer) { >> + timer_free(sd->timer); >> + sd->timer = NULL; >> + } >> + >> + audioOutput->open = 0; >> +} >> + >> +static void sendMetadata(ShoutData *sd) >> +{ >> + const size_t tag_size = 1024; >> + char song[tag_size]; >> + char artist[tag_size]; >> + char title[tag_size]; >> + >> + if (sd->tag) { >> + int i; >> + >> + for (i = 0; i < sd->tag->numOfItems; i++) { >> + switch (sd->tag->items[i].type) { >> + case TAG_ITEM_ARTIST: >> + snprintf(artist, tag_size, "%s", >> + sd->tag->items[i].value); >> + break; >> + case TAG_ITEM_TITLE: >> + snprintf(title, tag_size, "%s", >> + sd->tag->items[i].value); >> + break; >> + } >> + } >> + snprintf(song, tag_size, "%s - %s", title, artist); >> + shout_metadata_add(sd->shoutMeta, "song", song); >> + if (SHOUTERR_SUCCESS != shout_set_metadata(sd- >> >shoutConn, >> + sd- >> >shoutMeta)) { >> + ERROR("error setting shout_mp3 metadata\n"); >> + return; >> + } >> + } >> +} >> + >> +static int initEncoder(ShoutData * sd) >> +{ >> + if (NULL == (sd->gfp = lame_init())) { >> + ERROR("problem setting up lame encoder for >> shout_mp3\n"); >> + lame_close(sd->gfp); /* necessary? */ >> + return -1; >> + } >> + >> + if (sd->quality >= -1.0) { >> + if (0 != lame_set_VBR(sd->gfp, vbr_rh)) { >> + ERROR("problem setting up lame encoder for >> shout_mp3\n"); >> + lame_close(sd->gfp); >> + return -1; >> + } >> + if (0 != lame_set_VBR_q(sd->gfp, sd->quality)) { >> + ERROR("problem setting up lame encoder for >> shout_mp3\n"); >> + lame_close(sd->gfp); >> + return -1; >> + } >> + } else { >> + if (0 != lame_set_brate(sd->gfp, sd->bitrate)) { >> + ERROR("problem setting up lame encoder for >> shout_mp3\n"); >> + lame_close(sd->gfp); >> + return -1; >> + } >> + } >> + >> + if (0 != lame_set_num_channels(sd->gfp, >> + sd->audioFormat->channels)) { >> + ERROR("problem setting up lame encoder for shout >> \n"); >> + lame_close(sd->gfp); >> + return -1; >> + } >> + >> + if (0 != lame_set_in_samplerate(sd->gfp, >> + sd->audioFormat- >> >sampleRate)) { >> + ERROR("problem setting up lame encoder for shout >> \n"); >> + lame_close(sd->gfp); >> + return -1; >> + } >> + >> + if (0 > lame_init_params(sd->gfp)) { >> + ERROR("problem setting up lame encoder for shout >> \n"); >> + lame_close(sd->gfp); >> + return -1; >> + } >> + >> + return 0; >> +} >> + >> +static int myShoutMp3_connect(ShoutData *sd) >> +{ >> + time_t t = time(NULL); >> + int state = shout_get_connected(sd->shoutConn); >> + >> + /* already connected */ >> + if (state == SHOUTERR_CONNECTED) >> + return 0; >> + >> + /* waiting to connect */ >> + if (state == SHOUTERR_BUSY && sd->connAttempts != 0) { >> + /* timeout waiting to connect */ >> + if ((t - sd->lastAttempt) > sd->timeout) { >> + ERROR("timeout connecting to shout server >> %s:%i " >> + "(attempt %i)\n", >> + shout_get_host(sd->shoutConn), >> + shout_get_port(sd->shoutConn), >> + sd->connAttempts); >> + return -1; >> + } >> + >> + return 1; >> + } >> + >> + /* we're in some funky state, so just reset it to >> unconnected */ >> + if (state != SHOUTERR_UNCONNECTED) >> + shout_close(sd->shoutConn); >> + >> + /* throttle new connection attempts */ >> + if (sd->connAttempts != 0 && >> + (t - sd->lastAttempt) <= CONN_ATTEMPT_INTERVAL) { >> + return -1; >> + } >> + >> + /* initiate a new connection */ >> + >> + sd->connAttempts++; >> + sd->lastAttempt = t; >> + >> + state = shout_open(sd->shoutConn); >> + 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->shoutConn), >> + shout_get_port(sd->shoutConn), >> + sd->connAttempts, shout_get_error(sd- >> >shoutConn)); >> + return -1; >> + } >> +} >> + >> +static int myShoutMp3_openShoutConn(AudioOutput * audioOutput) >> +{ >> + ShoutData *sd = (ShoutData *) audioOutput->data; >> + int status; >> + >> + status = myShoutMp3_connect(sd); >> + if (status != 0) >> + return status; >> + >> + if (initEncoder(sd) < 0) { >> + shout_close(sd->shoutConn); >> + return -1; >> + } >> + >> + sd->shoutError = 0; >> + >> + sendMetadata(sd); >> + >> + sd->opened = 1; >> + sd->tagToSend = 0; >> + >> + while (lame_encode_flush(sd->gfp, sd->mp3buf, sd- >> >mp3buf_full)) { >> + if (write_page(sd) < 0) { >> + myShoutMp3_closeShoutConn(sd); >> + return -1; >> + } >> + } >> + >> + sd->connAttempts = 0; >> + >> + return 0; >> +} >> + >> +static int myShoutMp3_openDevice(AudioOutput * audioOutput) >> +{ >> + ShoutData *sd = (ShoutData *) audioOutput->data; >> + >> + if (!sd->opened && myShoutMp3_openShoutConn(audioOutput) < >> 0) >> + return -1; >> + >> + if (sd->timer) >> + timer_free(sd->timer); >> + >> + sd->timer = timer_new(&audioOutput->outAudioFormat); >> + >> + audioOutput->open = 1; >> + >> + return 0; >> +} >> + >> +static void myShoutMp3_sendMetadata(ShoutData * sd) >> +{ >> + if (!sd->opened || !sd->tag) >> + return; >> + >> + clearEncoder(sd); >> + if (initEncoder(sd) < 0) >> + return; >> + >> + sendMetadata(sd); >> + >> + while (lame_encode_flush(sd->gfp, sd->mp3buf, sd- >> >mp3buf_full)) { >> + if (write_page(sd) < 0) { >> + myShoutMp3_closeShoutConn(sd); >> + return -1; >> + } >> + } >> + >> + /*if(sd->tag) freeMpdTag(sd->tag); >> + sd->tag = NULL; */ >> + sd->tagToSend = 0; >> +} >> + >> +static int myShoutMp3_play(AudioOutput * audioOutput, >> + const char *playChunk, size_t size) >> +{ >> + unsigned int i; >> + int j; >> + ShoutData *sd = (ShoutData *) audioOutput->data; >> + float lamebuf[2][50000]; /* make me dynamic? */ >> + unsigned int samples; >> + int bytes = sd->audioFormat->bits / 8; >> + int status; >> + >> + if (!sd->timer->started) >> + timer_start(sd->timer); >> + >> + timer_add(sd->timer, size); >> + >> + if (sd->opened && sd->tagToSend) >> + myShoutMp3_sendMetadata(sd); >> + >> + if (!sd->opened) { >> + status = myShoutMp3_openShoutConn(audioOutput); >> + if (status < 0) { >> + myShoutMp3_closeDevice(audioOutput); >> + return -1; >> + } else if (status > 0) { >> + timer_sync(sd->timer); >> + return 0; >> + } >> + } >> + >> + samples = size / (bytes * sd->audioFormat->channels); >> + >> + /* this is for only 16-bit audio */ >> + >> + for (i = 0; i < samples; i++) { >> + for (j = 0; j < sd->audioFormat->channels; j++) { >> + lamebuf[j][i] = (*((mpd_sint16 *) >> playChunk)); >> + playChunk += bytes; >> + } >> + } >> + >> + if (0 > (sd->mp3buf_full = >> + (lame_encode_buffer_float(sd->gfp, lamebuf[0], >> lamebuf[1], >> + samples, sd->mp3buf, >> + MP3_BUF_SIZE)))) { >> + ERROR("problem encoding lame buffer for >> shout_mp3\n"); >> + lame_close(sd->gfp); >> + myShoutMp3_closeShoutConn(sd); >> + return -1; >> + } >> + >> + if (write_page(sd) < 0) { >> + myShoutMp3_closeDevice(audioOutput); >> + return -1; >> + } >> + >> + return 0; >> +} >> + >> +static void myShoutMp3_setTag(AudioOutput * audioOutput, MpdTag * >> tag) >> +{ >> + ShoutData *sd = (ShoutData *) audioOutput->data; >> + >> + if (sd->tag) >> + freeMpdTag(sd->tag); >> + sd->tag = NULL; >> + sd->tagToSend = 0; >> + >> + if (!tag) >> + return; >> + >> + sd->tag = mpdTagDup(tag); >> + sd->tagToSend = 1; >> +} >> + >> +AudioOutputPlugin shoutMp3Plugin = { >> + "shout_mp3", >> + NULL, >> + myShoutMp3_initDriver, >> + myShoutMp3_finishDriver, >> + myShoutMp3_openDevice, >> + myShoutMp3_play, >> + myShoutMp3_dropBufferedAudio, >> + myShoutMp3_closeDevice, >> + myShoutMp3_setTag, >> +}; >> + >> +#else >> + >> +DISABLED_AUDIO_OUTPUT_PLUGIN(shoutMp3Plugin) >> +#endif > > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v2.0.9 (GNU/Linux) > Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org > > iEYEARECAAYFAkizz24ACgkQ14/fqnT0YgOzuwCgiZphN8LZqPKKDUePZ5tnlcxn > /MMAn2LjEG5V1LQezG55DFs/eIhfG4PE > =PSgQ > -----END PGP SIGNATURE----- -- [EMAIL PROTECTED] "If the answer isn't violence, neither is your silence!" -- Pop Will Eat Itself, "Ich Bin Ein Auslander" ------------------------------------------------------------------------- This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/ _______________________________________________ Musicpd-dev-team mailing list Musicpd-dev-team@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team