diff options
-rw-r--r-- | configure.ac | 35 | ||||
-rw-r--r-- | m4/lame.m4 | 108 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/audioOutputs/audioOutput_shout.c | 1 | ||||
-rw-r--r-- | src/audioOutputs/audioOutput_shout.h | 1 | ||||
-rw-r--r-- | src/audioOutputs/audioOutput_shout_mp3.c | 194 |
6 files changed, 340 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index ffe161307..d98eb6486 100644 --- a/configure.ac +++ b/configure.ac @@ -74,6 +74,7 @@ fi AC_ARG_ENABLE(ao,[ --enable-ao enable support for libao (default: disable)],[enable_ao=$enableval],[enable_ao=no]) AC_ARG_ENABLE(shout_ogg,[ --disable-shout_ogg disable support for ogg streaming through shout (default: enable)],[enable_shout_ogg=$enableval],[enable_shout_ogg=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]) @@ -88,6 +89,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]) @@ -207,6 +209,20 @@ if test x$enable_shout_ogg = xyes; then fi fi +if test x$enable_shout_mp3 = xyes; then + if test x$enable_lame = xno; then + AC_MSG_WARN([disabling mp3 shout streaming support because lame is not enabled]) + enable_shout_mp3=no + fi + if test x$enable_shout = xno; then + AC_MSG_WARN([disabling mp3 shout streaming support because libshout is not found]) + enable_shout_mp3=no + fi + if test x$enable_shout_mp3 = xyes; then + AC_DEFINE(HAVE_SHOUT_MP3, 1, [Define to enable mp3 streaming support]) + 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 @@ -364,6 +380,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" @@ -753,11 +775,18 @@ else echo " Shout ogg 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_ogg = xno && + test x$enable_shout_mp3 = xno && test x$enable_alsa = xno && test x$enable_osx = xno && test x$enable_pulse = xno && @@ -781,6 +810,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 000000000..5ebf550df --- /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 097722dd8..272a63199 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,6 +4,7 @@ SUBDIRS = $(MP4FF_SUBDIR) mpd_audioOutputs = \ audioOutputs/audioOutput_shout.c \ audioOutputs/audioOutput_shout_ogg.c \ + audioOutputs/audioOutput_shout_mp3.c \ audioOutputs/audioOutput_null.c \ audioOutputs/audioOutput_fifo.c \ audioOutputs/audioOutput_alsa.c \ diff --git a/src/audioOutputs/audioOutput_shout.c b/src/audioOutputs/audioOutput_shout.c index 1e60e3546..82a68fa9f 100644 --- a/src/audioOutputs/audioOutput_shout.c +++ b/src/audioOutputs/audioOutput_shout.c @@ -113,6 +113,7 @@ static void free_shout_data(struct shout_data *sd) static void load_shout_plugins(void) { init_shout_encoder_plugins(); + load_shout_encoder_plugin(&shout_mp3_encoder); load_shout_encoder_plugin(&shout_ogg_encoder); } diff --git a/src/audioOutputs/audioOutput_shout.h b/src/audioOutputs/audioOutput_shout.h index c21ddff40..14f6b00a7 100644 --- a/src/audioOutputs/audioOutput_shout.h +++ b/src/audioOutputs/audioOutput_shout.h @@ -94,6 +94,7 @@ struct shout_data { shout_buffer buf; }; +extern shout_encoder_plugin shout_mp3_encoder; extern shout_encoder_plugin shout_ogg_encoder; #endif diff --git a/src/audioOutputs/audioOutput_shout_mp3.c b/src/audioOutputs/audioOutput_shout_mp3.c new file mode 100644 index 000000000..388808c1b --- /dev/null +++ b/src/audioOutputs/audioOutput_shout_mp3.c @@ -0,0 +1,194 @@ +/* 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 "../output_api.h" + +#ifdef HAVE_SHOUT_MP3 + +#include "../utils.h" +#include "audioOutput_shout.h" +#include <lame/lame.h> + +typedef struct _lame_data { + lame_global_flags *gfp; +} lame_data; + + +static int shout_mp3_encoder_init(shout_data * sd) +{ + lame_data *ld; + + if (NULL == (ld = xmalloc(sizeof(lame_data)))) + FATAL("error initializing lame encoder data\n"); + sd->encoder_data = ld; + + return 0; +} + +static int shout_mp3_encoder_clear_encoder(shout_data * sd) +{ + lame_data *ld = (lame_data *)sd->encoder_data; + shout_buffer *buf = &sd->buf; + int ret; + + if ((ret = lame_encode_flush(ld->gfp, buf->data + buf->len, + buf->len)) < 0) + ERROR("error flushing lame buffers\n"); + + return (ret > 0); +} + +static void shout_mp3_encoder_finish(shout_data * sd) +{ + lame_data *ld = (lame_data *)sd->encoder_data; + + lame_close(ld->gfp); + ld->gfp = NULL; +} + +static int shout_mp3_encoder_init_encoder(shout_data * sd) +{ + lame_data *ld = (lame_data *)sd->encoder_data; + + if (NULL == (ld->gfp = lame_init())) { + ERROR("error initializing lame encoder for shout\n"); + return -1; + } + + if (sd->quality >= -1.0) { + if (0 != lame_set_VBR(ld->gfp, vbr_rh)) { + ERROR("error setting lame VBR mode\n"); + return -1; + } + if (0 != lame_set_VBR_q(ld->gfp, sd->quality)) { + ERROR("error setting lame VBR quality\n"); + return -1; + } + } else { + if (0 != lame_set_brate(ld->gfp, sd->bitrate)) { + ERROR("error setting lame bitrate\n"); + return -1; + } + } + + if (0 != lame_set_num_channels(ld->gfp, + sd->audio_format.channels)) { + ERROR("error setting lame num channels\n"); + return -1; + } + + if (0 != lame_set_in_samplerate(ld->gfp, + sd->audio_format.sampleRate)) { + ERROR("error setting lame sample rate\n"); + return -1; + } + + if (0 > lame_init_params(ld->gfp)) + FATAL("error initializing lame params\n"); + + return 0; +} + +static int shout_mp3_encoder_send_metadata(shout_data * sd, + char * song, size_t size) +{ + char artist[size]; + char title[size]; + int i; + struct tag *tag = sd->tag; + + strncpy(artist, "", size); + strncpy(title, "", size); + + for (i = 0; i < tag->numOfItems; i++) { + switch (tag->items[i]->type) { + case TAG_ITEM_ARTIST: + strncpy(artist, tag->items[i]->value, size); + break; + case TAG_ITEM_TITLE: + strncpy(title, tag->items[i]->value, size); + break; + + default: + break; + } + } + snprintf(song, size, "%s - %s", title, artist); + + return 1; +} + +static int shout_mp3_encoder_encode(shout_data * sd, + const char * chunk, size_t len) +{ + unsigned int i; + int j; + float (*lamebuf)[2]; + shout_buffer *buf = &(sd->buf); + unsigned int samples; + int bytes = sd->audio_format.bits / 8; + lame_data *ld = (lame_data *)sd->encoder_data; + int bytes_out; + + samples = len / (bytes * sd->audio_format.channels); + /* rough estimate, from lame.h */ + lamebuf = xmalloc(sizeof(float) * (1.25 * samples + 7200)); + + /* this is for only 16-bit audio */ + + for (i = 0; i < samples; i++) { + for (j = 0; j < sd->audio_format.channels; j++) { + lamebuf[j][i] = *((const mpd_sint16 *) chunk); + chunk += bytes; + } + } + + bytes_out = lame_encode_buffer_float(ld->gfp, lamebuf[0], lamebuf[1], + samples, buf->data, + buf->max_len - buf->len); + free(lamebuf); + + if (0 > bytes_out) { + ERROR("error encoding lame buffer for shout\n"); + lame_close(ld->gfp); + ld->gfp = NULL; + return -1; + } else + buf->len = bytes_out; /* signed to unsigned conversion */ + + return 0; +} + + +shout_encoder_plugin shout_mp3_encoder = { + "mp3", + SHOUT_FORMAT_MP3, + + shout_mp3_encoder_clear_encoder, + shout_mp3_encoder_encode, + shout_mp3_encoder_finish, + shout_mp3_encoder_init, + shout_mp3_encoder_init_encoder, + shout_mp3_encoder_send_metadata, +}; + +#else + +DISABLED_SHOUT_ENCODER_PLUGIN(shout_mp3_encoder); + +#endif |