-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 after the weekend I can do more testing if you want.
Q EAW wrote: > 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: > > 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 > -- > [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 -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.9 (GNU/Linux) Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org iEYEARECAAYFAki1vH8ACgkQ14/fqnT0YgM+ngCeO4MLRa1C/JDiuPLADVhrNFND lnkAnAnkGxJ0HcI9DDRFbQlI/Br7Tbmv =IlWC -----END PGP SIGNATURE----- ------------------------------------------------------------------------- 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