Commit f669096f authored by Led's avatar Led

0.10.2-rc1

parent e990dced
......@@ -4,3 +4,6 @@ wave File Support -> normalperson
setuid patch -> Nagilum
'next' and 'previous' patch -> Niklas Hofer
command.c cleanup -> mackstann
libid3tag and libmad copyrighted by Robert Leslie, http://www.underbit.com/products/mad
mp4ff copyrighted by M. Bakker, Ahead Software AG, http://www.nero.com
ver 0.10.2 (2004/3/25)
1) Add suport for AAC
2) Substitute '\n' with ' ' int tag info
3) Remove empty directories from db
4) Resume from current position in song when using state file
5) Pause now closes the music device, and reopens it on resuming
6) Fix unnecessary big endian byte swapping
7) If locale is "C" or "POSIX", then use ISO-8859-1 as the fs charset
ver 0.10.1 (2004/3/7)
1) Check to see if we need to add "-lm" when linking mpd
2) Fix issues with skipping bad frames in an mp3 (this way we get the correct samplerate and such)
......
......@@ -25,6 +25,9 @@ libogg, libogg-devel, libvorbis, and libvorbis-devel).
Flac - http://flac.sf.net
For Flac support, you need Flac 1.1.0 or greater.
FAAD2 - http://faac.sf.net
For MP4/AAC support.
Audiofile - http://www.68k.org/~michael/audiofile/
For wave support.
......
AUTOMAKE_OPTIONS = foreign 1.6 dist-bzip2
SUBDIRS = src doc
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = README UPGRADING
......
......@@ -9,8 +9,11 @@ retrieval, and playlist management can all be managed remotely.
To install MPD, see INSTALL.
MPD includes 2 libraries in the source. libid3tag and libmad are released under
MPD includes 3 libraries in the source. libid3tag and libmad are released under
the GPL and copyrighted by Robert Leslie (http://www.underbit.com/products/mad).
mp4ff is released under the GPL and copyrighted by M. Bakker, Ahead Software AG
(http://www.nero.com) and is distributed as a part of the FAAD2 - Freeware
Advance Audio (AAC) Decoder.
MPD is released under the GNU Public License.
You should have received a copy of the GNU General Public License
......
1) 24-bit pcm-tools (this may just wait since almost no one uses it)
2?) put software mixer settings in state file
3) Dealing with symlinks and new db:
a) id3 talbe: artist->album->song
song: key->title,
data->tag (add SongList of symlinks)
b) check for symlinks by comparing realpaths
c) when writing songs to db, put duplicate links
d) when reading db, check duplicate links, if duplicate link,
then just copy the tag.
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if alsa support is present */
#undef HAVE_ALSA
/* Define for audiofile support */
#undef HAVE_AUDIOFILE
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
/* Define to 1 if you have the `dlopen' function. */
#undef HAVE_DLOPEN
/* Define to 1 if `dontUpSampleImplicitSBR' is member of
`faacDecConfiguration'. */
#undef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
/* Define to 1 if `downMatrix' is member of `faacDecConfiguration'. */
#undef HAVE_FAACDECCONFIGURATION_DOWNMATRIX
/* Define to use FAAD2 for AAC decoding */
#undef HAVE_FAAD
/* Define for FLAC support */
#undef HAVE_FLAC
/* Define to use iconv */
#undef HAVE_ICONV
/* Define to use id3tag */
#undef HAVE_ID3TAG
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define if IPv6 support present */
#undef HAVE_IPV6
/* Define if nl_langinfo.h is present */
#undef HAVE_LANGINFO
/* Define to 1 if you have the `FLAC' library (-lFLAC). */
#undef HAVE_LIBFLAC
/* Define if locale.h is present */
#undef HAVE_LOCALE
/* Define to use libmad */
#undef HAVE_MAD
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define for ogg vorbis support */
#undef HAVE_OGG
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to disable OSS mixer support */
#undef NO_OSS_MIXER
/* Name of package */
#undef PACKAGE
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* The size of a `int', as computed by sizeof. */
#undef SIZEOF_INT
/* The size of a `long', as computed by sizeof. */
#undef SIZEOF_LONG
/* The size of a `long long', as computed by sizeof. */
#undef SIZEOF_LONG_LONG
/* The size of a `short', as computed by sizeof. */
#undef SIZEOF_SHORT
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to use mpd libid3tag */
#undef USE_MPD_ID3TAG
/* Define to use mpd libmad */
#undef USE_MPD_MAD
/* Version number of package */
#undef VERSION
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
#undef WORDS_BIGENDIAN
#! /bin/sh
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002 Free Software Foundation, Inc.
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
timestamp='2002-09-05'
timestamp='2003-01-03'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
......@@ -118,7 +118,7 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | freebsd*-gnu* | storm-chaos* | os2-emx* | windows32-* | rtmk-nova*)
nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
......@@ -245,16 +245,19 @@ case $basic_machine in
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa64 | mipsisa64el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| msp430 \
| ns16k | ns32k \
| openrisc | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
| s390 | s390x \
| sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
......@@ -315,16 +318,19 @@ case $basic_machine in
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39 | mipstx39el \
| none-* | np1-* | ns16k-* | ns32k-* \
| mipstx39-* | mipstx39el-* \
| msp430-* \
| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| romp-* | rs6000-* \
| s390-* | s390x-* \
| sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
......@@ -367,9 +373,6 @@ case $basic_machine in
basic_machine=a29k-none
os=-bsd
;;
amd64-*)
basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
amdahl)
basic_machine=580-amdahl
os=-sysv
......@@ -719,6 +722,10 @@ case $basic_machine in
np1)
basic_machine=np1-gould
;;
nv1)
basic_machine=nv1-cray
os=-unicosmp
;;
nsr-tandem)
basic_machine=nsr-tandem
;;
......@@ -815,12 +822,6 @@ case $basic_machine in
rtpc | rtpc-*)
basic_machine=romp-ibm
;;
s390 | s390-*)
basic_machine=s390-ibm
;;
s390x | s390x-*)
basic_machine=s390x-ibm
;;
sa29200)
basic_machine=a29k-amd
os=-udi
......@@ -904,10 +905,6 @@ case $basic_machine in
basic_machine=i386-sequent
os=-dynix
;;
t3d)
basic_machine=alpha-cray
os=-unicos
;;
t3e)
basic_machine=alphaev5-cray
os=-unicos
......@@ -980,10 +977,6 @@ case $basic_machine in
basic_machine=hppa1.1-winbond
os=-proelf
;;
windows32)
basic_machine=i386-pc
os=-windows32-msvcrt
;;
xps | xps100)
basic_machine=xps100-honeywell
;;
......@@ -1116,11 +1109,12 @@ case $os in
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* | -powermax*)
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -microbsd*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
......@@ -1132,8 +1126,10 @@ case $os in
;;
esac
;;
-nto-qnx*)
;;
-nto*)
os=-nto-qnx
os=`echo $os | sed -e 's|nto|nto-qnx|'`
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
......
This source diff could not be displayed because it is too large. You can view the blob instead.
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
# Copyright 1999, 2000, 2003 Free Software Foundation, Inc.
# Copyright 1999, 2000 Free Software Foundation, Inc.
# 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
......@@ -172,25 +172,19 @@ sgi)
aix)
# The C for AIX Compiler uses -M and outputs the dependencies
# in a .u file. In older versions, this file always lives in the
# current directory. Also, the AIX compiler puts `$object:' at the
# start of each line; $object doesn't have directory information.
# Version 6 uses the directory in both cases.
stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
# in a .u file. This file always lives in the current directory.
# Also, the AIX compiler puts `$object:' at the start of each line;
# $object doesn't have directory information.
stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
tmpdepfile="$stripped.u"
outname="$stripped.o"
if test "$libtool" = yes; then
"$@" -Wc,-M
else
"$@" -M
fi
stat=$?
if test -f "$tmpdepfile"; then :
else
stripped=`echo "$stripped" | sed 's,^.*/,,'`
tmpdepfile="$stripped.u"
fi
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
......@@ -198,7 +192,6 @@ aix)
fi
if test -f "$tmpdepfile"; then
outname="$stripped.o"
# Each line is of the form `foo.o: dependent.h'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
......@@ -213,44 +206,6 @@ aix)
rm -f "$tmpdepfile"
;;
icc)
# Intel's C compiler understands `-MD -MF file'. However on
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
# ICC 7.0 will fill foo.d with something like
# foo.o: sub/foo.c
# foo.o: sub/foo.h
# which is wrong. We want:
# sub/foo.o: sub/foo.c
# sub/foo.o: sub/foo.h
# sub/foo.c:
# sub/foo.h:
# ICC 7.1 will output
# foo.o: sub/foo.c sub/foo.h
# and will wrap long lines using \ :
# foo.o: sub/foo.c ... \
# sub/foo.h ... \
# ...
"$@" -MD -MF "$tmpdepfile"
stat=$?
if test $stat -eq 0; then :
else
rm -f "$tmpdepfile"
exit $stat
fi
rm -f "$depfile"
# Each line is of the form `foo.o: dependent.h',
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
# Do two passes, one to just change these to
# `$object: dependent.h' and one to simply `dependent.h:'.
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
# Some versions of the HPUX 10.20 sed can't process this invocation
# correctly. Breaking it into two sed invocations is a workaround.
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
sed -e 's/$/ :/' >> "$depfile"
rm -f "$tmpdepfile"
;;
tru64)
# The Tru64 compiler uses -MD to generate dependencies as a side
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
......@@ -285,8 +240,8 @@ tru64)
fi
if test -f "$tmpdepfile"; then
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
# That's a tab and a space in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
# That's a space and a tab in the [].
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
else
echo "#dummy" > "$depfile"
fi
......@@ -299,7 +254,7 @@ tru64)
dashmstdout)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o.
# always write the proprocessed file to stdout, regardless of -o.
"$@" || exit $?
# Remove the call to Libtool.
......@@ -310,7 +265,9 @@ dashmstdout)
shift
fi
# Remove `-o $object'.
# Remove `-o $object'. We will use -o /dev/null later,
# however we can't do the remplacement now because
# `-o $object' might simply not be used
IFS=" "
for arg
do
......@@ -330,11 +287,7 @@ dashmstdout)
done
test -z "$dashmflag" && dashmflag=-M
# Require at least two characters before searching for `:'
# in the target name. This is to cope with DOS-style filenames:
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
"$@" $dashmflag |
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
"$@" -o /dev/null $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
rm -f "$depfile"
cat < "$tmpdepfile" > "$depfile"
tr ' ' '
......@@ -353,13 +306,6 @@ dashXmstdout)
makedepend)
"$@" || exit $?
# Remove any Libtool call
if test "$libtool" = yes; then
while test $1 != '--mode=compile'; do
shift
done
shift
fi
# X makedepend
shift
cleared=no
......@@ -372,9 +318,7 @@ makedepend)
case "$arg" in
-D*|-I*)
set fnord "$@" "$arg"; shift ;;
# Strip any option that makedepend may not understand. Remove
# the object too, otherwise makedepend will parse it as a source file.
-*|$object)
-*)
;;
*)
set fnord "$@" "$arg"; shift ;;
......@@ -395,7 +339,7 @@ makedepend)
cpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout.
# always write the proprocessed file to stdout.
"$@" || exit $?
# Remove the call to Libtool.
......@@ -437,7 +381,7 @@ cpp)
msvisualcpp)
# Important note: in order to support this mode, a compiler *must*
# always write the preprocessed file to stdout, regardless of -o,
# always write the proprocessed file to stdout, regardless of -o,
# because we must use -o when running libtool.
"$@" || exit $?
IFS=" "
......
......@@ -6,11 +6,19 @@ Format:
-------
If arguments contain spaces, they should be surrounded by double quotation
marks, ".
marks, ".
command <type arg1> <type arg2> ...
explanation: w/ arg1 and arg2
All data between the client and server is encoded in UTF-8. (Note,
that in UTF-8 all standard ansi characters, 0-127, are the same as a standard
ansi encoding. Also, no ansi character appears in any multi-byte
characters. So, you can use standard C functions like strlen, and strcpy
just fine with UTF-8 encoded strings. For example: "OK\n" encoded in UTF-8 is
simply "OK\n". For more information on UTF=8:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 )
Command Completion:
-------------------
......@@ -165,6 +173,7 @@ swap <int song1> <int song2>
update
searches mp3 directory for new music and removes old music from the db
increments playlist version by 1
volume <int change>
change volume by amount _change_
......
# Makefile.in generated by automake 1.7.8 from Makefile.am.
# Makefile.in generated by automake 1.6.3 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
# Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
......@@ -13,139 +13,106 @@
# PARTICULAR PURPOSE.
@SET_MAKE@
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
host_triplet = @host@
ACLOCAL = @ACLOCAL@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@
AO_CFLAGS = @AO_CFLAGS@
AO_LIBS = @AO_LIBS@
AS = @AS@
AUDIOFILE_CFLAGS = @AUDIOFILE_CFLAGS@
AUDIOFILE_CONFIG = @AUDIOFILE_CONFIG@
AUDIOFILE_LIBS = @AUDIOFILE_LIBS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
ID3_LIB = @ID3_LIB@
ID3_SUBDIR = @ID3_SUBDIR@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBFLAC_CFLAGS = @LIBFLAC_CFLAGS@
LIBFLAC_LIBS = @LIBFLAC_LIBS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAD_LIB = @MAD_LIB@
MAD_SUBDIR = @MAD_SUBDIR@
MAKEINFO = @MAKEINFO@
MP4FF_LIB = @MP4FF_LIB@
MP4FF_SUBDIR = @MP4FF_SUBDIR@
MPD_CFLAGS = @MPD_CFLAGS@
MPD_LIBS = @MPD_LIBS@
OBJEXT = @OBJEXT@
OBJDUMP = @OBJDUMP@
OGG_CFLAGS = @OGG_CFLAGS@
OGG_LIBS = @OGG_LIBS@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
VORBISENC_LIBS = @VORBISENC_LIBS@
VORBISFILE_LIBS = @VORBISFILE_LIBS@
VORBIS_CFLAGS = @VORBIS_CFLAGS@
VORBIS_LIBS = @VORBIS_LIBS@
ac_ct_CC = @ac_ct_CC@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
oldincludedir = @oldincludedir@
prefix = @prefix@
program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
subdirs = @subdirs@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
man_MANS = mpd.1
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = COMMANDS
EXTRA_DIST = mpdconf.example $(man_MANS) $(doc_DATA)
subdir = doc
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
DIST_SOURCES =
......@@ -153,13 +120,13 @@ NROFF = nroff
MANS = $(man_MANS)
DATA = $(doc_DATA)
DIST_COMMON = $(srcdir)/Makefile.in Makefile.am
DIST_COMMON = Makefile.am Makefile.in
all: all-am
.SUFFIXES:
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.ac $(ACLOCAL_M4)
cd $(top_srcdir) && \
$(AUTOMAKE) --foreign doc/Makefile
$(AUTOMAKE) --gnu doc/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
......@@ -209,10 +176,6 @@ uninstall-man1:
done; \
for i in $$list; do \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
case "$$ext" in \
1*) ;; \
*) ext='1' ;; \
esac; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
......@@ -240,22 +203,13 @@ uninstall-docDATA:
tags: TAGS
TAGS:
ctags: CTAGS
CTAGS:
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
esac; \
@list='$(DISTFILES)'; for file in $$list; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
......@@ -281,6 +235,7 @@ all-am: Makefile $(MANS) $(DATA)
installdirs:
$(mkinstalldirs) $(DESTDIR)$(man1dir) $(DESTDIR)$(docdir)
install: install-am
install-exec: install-exec-am
install-data: install-data-am
......@@ -300,7 +255,7 @@ mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f $(CONFIG_CLEAN_FILES)
-rm -f Makefile $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
......@@ -310,7 +265,7 @@ clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
-rm -f Makefile
distclean-am: clean-am distclean-generic distclean-libtool
dvi: dvi-am
......@@ -332,21 +287,13 @@ install-man: install-man1
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-docDATA uninstall-info-am uninstall-man
uninstall-man: uninstall-man1
......@@ -358,9 +305,9 @@ uninstall-man: uninstall-man1
install-info install-info-am install-man install-man1 \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
uninstall uninstall-am uninstall-docDATA uninstall-info-am \
uninstall-man uninstall-man1
mostlyclean-generic mostlyclean-libtool uninstall uninstall-am \
uninstall-docDATA uninstall-info-am uninstall-man \
uninstall-man1
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
......
#!/bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5 (mit/util/scripts/install.sh).
#
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
# Copyright 1991 by the Massachusetts Institute of Technology
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation, and that the name of M.I.T. not be used in advertising or
# publicity pertaining to distribution of the software without specific,
# written prior permission. M.I.T. makes no representations about the
# suitability of this software for any purpose. It is provided "as is"
# without express or implied warranty.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
......@@ -74,7 +56,7 @@ dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd=$cpprog
-c) instcmd="$cpprog"
shift
continue;;
......@@ -97,7 +79,7 @@ while [ x"$1" != x ]; do
shift
continue;;
-s) stripcmd=$stripprog
-s) stripcmd="$stripprog"
shift
continue;;
......@@ -124,7 +106,7 @@ done
if [ x"$src" = x ]
then
echo "$0: no input file specified" >&2
echo "install: no input file specified"
exit 1
else
:
......@@ -133,8 +115,8 @@ fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d "$dst" ]; then
if [ -d $dst ]; then
instcmd=:
chmodcmd=""
else
......@@ -143,20 +125,20 @@ if [ x"$dir_arg" != x ]; then
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f "$src" ] || [ -d "$src" ]
then
:
else
echo "$0: $src does not exist" >&2
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "$0: no destination specified" >&2
echo "install: no destination specified"
exit 1
else
:
......@@ -165,16 +147,16 @@ else
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d "$dst" ]
if [ -d $dst ]
then
dst=$dst/`basename "$src"`
dst="$dst"/`basename $src`
else
:
fi
fi
## this sed command emulates the dirname command
dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
......@@ -183,73 +165,69 @@ dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-$defaultIFS}"
IFS="${IFS-${defaultIFS}}"
oIFS=$IFS
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS=$oIFS
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp=$pathcomp$1
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "$pathcomp" ] ;
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "$pathcomp"
$mkdirprog "${pathcomp}"
else
:
fi
pathcomp=$pathcomp/
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd "$dst" &&
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
if [ x"$transformarg" = x ]
then
dstfile=`basename "$dst"`
dstfile=`basename $dst`
else
dstfile=`basename "$dst" $transformbasename |
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
if [ x"$dstfile" = x ]
then
dstfile=`basename "$dst"`
dstfile=`basename $dst`
else
:
fi
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Make a temp file name in the proper directory.
# Trap to clean up temp files at exit.
trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
trap '(exit $?); exit' 1 2 13 15
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd "$src" "$dsttmp" &&
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
......@@ -257,38 +235,17 @@ else
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
# Now remove or move aside any old file at destination location. We try this
# two ways since rm can't unlink itself on some systems and the destination
# file might be busy for other reasons. In this case, the final cleanup
# might fail but the new file should still install successfully.
{
if [ -f "$dstdir/$dstfile" ]
then
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
$doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
{
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
(exit 1); exit
}
else
:
fi
} &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
# The final little trick to "correctly" pass the exit status to the exit trap.
{
(exit 0); exit
}
exit 0
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
# Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
......@@ -165,7 +165,7 @@ WARNING: \`$1' is missing on your system. You should only need it if
WARNING: \`$1' is needed, and you do not seem to have it handy on your
system. You might have modified some files without having the
proper tools for further handling them.
You can get \`$1' as part of \`Autoconf' from any GNU
You can get \`$1Help2man' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
......@@ -326,7 +326,7 @@ WARNING: I can't seem to be able to run \`tar' with the given arguments.
WARNING: \`$1' is needed, and you do not seem to have it handy on your
system. You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequisites for installing
it often tells you about the needed prerequirements for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
......
......@@ -12,29 +12,18 @@ Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..."
# process command line arguments
while test $# -gt 0 ; do
case $1 in
-h | --help | --h*) # -h for help
echo "$usage" 1>&2
exit 0
;;
-m) # -m PERM arg
shift
test $# -eq 0 && { echo "$usage" 1>&2; exit 1; }
dirmode=$1
shift
;;
--) # stop option processing
shift
break
;;
-*) # unknown option
echo "$usage" 1>&2
exit 1
;;
*) # first non-opt arg
break
;;
esac
case "${1}" in
-h | --help | --h* ) # -h for help
echo "${usage}" 1>&2; exit 0 ;;
-m ) # -m PERM arg
shift
test $# -eq 0 && { echo "${usage}" 1>&2; exit 1; }
dirmode="${1}"
shift ;;
-- ) shift; break ;; # stop option processing
-* ) echo "${usage}" 1>&2; exit 1 ;; # unknown option
* ) break ;; # first non-opt arg
esac
done
for file
......@@ -47,65 +36,64 @@ do
done
case $# in
0) exit 0 ;;
0) exit 0 ;;
esac
case $dirmode in
'')
if mkdir -p -- . 2>/dev/null; then
echo "mkdir -p -- $*"
exec mkdir -p -- "$@"
fi
;;
*)
if mkdir -m "$dirmode" -p -- . 2>/dev/null; then
echo "mkdir -m $dirmode -p -- $*"
exec mkdir -m "$dirmode" -p -- "$@"
fi
;;
'')
if mkdir -p -- . 2>/dev/null; then
echo "mkdir -p -- $*"
exec mkdir -p -- "$@"
fi ;;
*)
if mkdir -m "$dirmode" -p -- . 2>/dev/null; then
echo "mkdir -m $dirmode -p -- $*"
exec mkdir -m "$dirmode" -p -- "$@"
fi ;;
esac
for file
do
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
shift
pathcomp=
for d
do
pathcomp="$pathcomp$d"
case $pathcomp in
-*) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp"
mkdir "$pathcomp" || lasterr=$?
if test ! -d "$pathcomp"; then
errstatus=$lasterr
else
if test ! -z "$dirmode"; then
echo "chmod $dirmode $pathcomp"
lasterr=""
chmod "$dirmode" "$pathcomp" || lasterr=$?
if test ! -z "$lasterr"; then
errstatus=$lasterr
fi
fi
fi
fi
pathcomp="$pathcomp/"
done
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
shift
pathcomp=
for d
do
pathcomp="$pathcomp$d"
case "$pathcomp" in
-* ) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp"
mkdir "$pathcomp" || lasterr=$?
if test ! -d "$pathcomp"; then
errstatus=$lasterr
else
if test ! -z "$dirmode"; then
echo "chmod $dirmode $pathcomp"
lasterr=""
chmod "$dirmode" "$pathcomp" || lasterr=$?
if test ! -z "$lasterr"; then
errstatus=$lasterr
fi
fi
fi
fi
pathcomp="$pathcomp/"
done
done
exit $errstatus
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# sh-indentation: 3
# End:
# mkinstalldirs ends here
bin_PROGRAMS = mpd
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR)
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR) $(MP4FF_SUBDIR)
mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \
song.h list.h directory.h tables.h utils.h path.h mp3_decode.h \
tag.h player.h listen.h conf.h ogg_decode.h volume.h flac_decode.h \
audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.h \
audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h
audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h \
mp4_decode.h aac_decode.h
mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \
song.c list.c directory.c tables.c utils.c path.c mp3_decode.c \
tag.c player.c listen.c conf.c ogg_decode.c volume.c flac_decode.c \
audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \
audiofile_decode.c charConv.c permission.c pcm_utils.c $(mpd_headers)
audiofile_decode.c charConv.c permission.c pcm_utils.c mp4_decode.c \
aac_decode.c $(mpd_headers)
mpd_CFLAGS = $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB)
DIST_SUBDIRS = mp4ff $(ID3_SUBDIR) $(MAD_SUBDIR)
This source diff could not be displayed because it is too large. You can view the blob instead.
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* 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 "aac_decode.h"
#ifdef HAVE_FAAD
#define AAC_MAX_CHANNELS 6
#include "command.h"
#include "utils.h"
#include "audio.h"
#include "log.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <faad.h>
/* all code here is either based on or copied from FAAD2's frontend code */
typedef struct {
long bytesIntoBuffer;
long bytesConsumed;
long fileOffset;
unsigned char *buffer;
int atEof;
FILE *infile;
} AacBuffer;
void fillAacBuffer(AacBuffer *b) {
if(b->bytesConsumed > 0) {
int bread;
if(b->bytesIntoBuffer) {
memmove((void *)b->buffer,(void*)(b->buffer+
b->bytesConsumed),b->bytesIntoBuffer);
}
if(!b->atEof) {
bread = fread((void *)(b->buffer+b->bytesIntoBuffer),1,
b->bytesConsumed,b->infile);
if(bread!=b->bytesConsumed) b->atEof = 1;
b->bytesIntoBuffer+=bread;
}
b->bytesConsumed = 0;
if(b->bytesIntoBuffer > 3) {
if(memcmp(b->buffer,"TAG",3)==0) b->bytesIntoBuffer = 0;
}
if(b->bytesIntoBuffer > 11) {
if(memcmp(b->buffer,"LYRICSBEGIN",11)==0) {
b->bytesIntoBuffer = 0;
}
}
if(b->bytesIntoBuffer > 8) {
if(memcmp(b->buffer,"APETAGEX",8)==0) {
b->bytesIntoBuffer = 0;
}
}
}
}
void advanceAacBuffer(AacBuffer * b, int bytes) {
b->fileOffset+=bytes;
b->bytesConsumed = bytes;
b->bytesIntoBuffer-=bytes;
}
static int adtsSampleRates[] = {96000,88200,64000,48000,44100,32000,24000,22050,
16000,12000,11025,8000,7350,0,0,0};
int adtsParse(AacBuffer * b, float * length) {
int frames, frameLength;
int tFrameLength = 0;
int sampleRate = 0;
float framesPerSec, bytesPerFrame;
/* Read all frames to ensure correct time and bitrate */
for(frames = 0; ;frames++) {
fillAacBuffer(b);
if(b->bytesIntoBuffer > 7) {
/* check syncword */
if (!((b->buffer[0] == 0xFF) &&
((b->buffer[1] & 0xF6) == 0xF0)))
{
break;
}
if(frames==0) {
sampleRate = adtsSampleRates[
(b->buffer[2]&0x3c)>>2];
}
frameLength = ((((unsigned int)b->buffer[3] & 0x3))
<< 11) | (((unsigned int)b->buffer[4])
<< 3) | (b->buffer[5] >> 5);
tFrameLength+=frameLength;
if(frameLength > b->bytesIntoBuffer) break;
advanceAacBuffer(b,frameLength);
}
else break;
}
framesPerSec = (float)sampleRate/1024.0;
if(frames!=0) {
bytesPerFrame = (float)tFrameLength/(float)(frames*1000);
}
else bytesPerFrame = 0;
if(framesPerSec!=0) *length = (float)frames/framesPerSec;
return 1;
}
void initAacBuffer(FILE * fp, AacBuffer * b, float * length,
size_t * retFileread, size_t * retTagsize)
{
size_t fileread;
size_t bread;
size_t tagsize;
if(length) *length = -1;
memset(b,0,sizeof(AacBuffer));
b->infile = fp;
fseek(b->infile,0,SEEK_END);
fileread = ftell(b->infile);
fseek(b->infile,0,SEEK_SET);
b->buffer = malloc(FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
memset(b->buffer,0,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
bread = fread(b->buffer,1,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS,
b->infile);
b->bytesIntoBuffer = bread;
b->bytesConsumed = 0;
b->fileOffset = 0;
if(bread!=FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS) b->atEof = 1;
tagsize = 0;
if(!memcmp(b->buffer,"ID3",3)) {
tagsize = (b->buffer[6] << 21) | (b->buffer[7] << 14) |
(b->buffer[8] << 7) | (b->buffer[9] << 0);
tagsize+=10;
advanceAacBuffer(b,tagsize);
fillAacBuffer(b);
}
if(retFileread) *retFileread = fileread;
if(retTagsize) *retTagsize = tagsize;
if(length==NULL) return;
if((b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0)) {
adtsParse(b, length);
fseek(b->infile, tagsize, SEEK_SET);
bread = fread(b->buffer, 1,
FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS,
b->infile);
if(bread != FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS) b->atEof = 1;
else b->atEof = 0;
b->bytesIntoBuffer = bread;
b->bytesConsumed = 0;
b->fileOffset = tagsize;
}
else if(memcmp(b->buffer,"ADIF",4) == 0) {
int bitRate;
int skipSize = (b->buffer[4] & 0x80) ? 9 : 0;
bitRate = ((unsigned int)(b->buffer[4 + skipSize] & 0x0F)<<19) |
((unsigned int)b->buffer[5 + skipSize]<<11) |
((unsigned int)b->buffer[6 + skipSize]<<3) |
((unsigned int)b->buffer[7 + skipSize] & 0xE0);
*length = fileread;
if(*length!=0 && bitRate!=0) *length = *length*8.0/bitRate;
}
}
float getAacFloatTotalTime(char * file) {
AacBuffer b;
float length;
size_t fileread, tagsize;
faacDecHandle decoder;
faacDecConfigurationPtr config;
unsigned long sampleRate;
unsigned char channels;
FILE * fp = fopen(file,"r");
if(fp==NULL) return -1;
initAacBuffer(fp,&b,&length,&fileread,&tagsize);
if(length < 0) {
decoder = faacDecOpen();
config = faacDecGetCurrentConfiguration(decoder);
config->outputFormat = FAAD_FMT_16BIT;
faacDecSetConfiguration(decoder,config);
fillAacBuffer(&b);
if(faacDecInit(decoder,b.buffer,b.bytesIntoBuffer,
&sampleRate,&channels) >= 0 &&
sampleRate > 0 && channels > 0)
{
length = 0;
}
faacDecClose(decoder);
}
if(b.buffer) free(b.buffer);
fclose(b.infile);
return length;
}
int getAacTotalTime(char * file) {
int time = -1;
float length;
if((length = getAacFloatTotalTime(file))>=0) time = length+0.5;
return time;
}
int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
float time;
float totalTime;
faacDecHandle decoder;
faacDecFrameInfo frameInfo;
faacDecConfigurationPtr config;
size_t bread;
unsigned long sampleRate;
unsigned char channels;
int eof = 0;
unsigned int sampleCount;
char * sampleBuffer;
size_t sampleBufferLen;
int chunkLen = 0;
/*float * seekTable;
long seekTableEnd = -1;
int seekPositionFound = 0;*/
mpd_uint16 bitRate = 0;
AacBuffer b;
FILE * fp;
if((totalTime = getAacFloatTotalTime(dc->file)) < 0) return -1;
fp = fopen(dc->file,"r");
if(fp==NULL) return -1;
initAacBuffer(fp,&b,NULL,NULL,NULL);
decoder = faacDecOpen();
config = faacDecGetCurrentConfiguration(decoder);
config->outputFormat = FAAD_FMT_16BIT;
#ifdef HAVE_FAACDECCONFIGURATION_DOWNMATRIX
config->downMatrix = 1;
#endif
#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
config->dontUpSampleImplicitSBR = 0;
#endif
faacDecSetConfiguration(decoder,config);
fillAacBuffer(&b);
if((bread = faacDecInit(decoder,b.buffer,b.bytesIntoBuffer,
&sampleRate,&channels)) < 0)
{
ERROR("Error not a AAC stream.\n");
faacDecClose(decoder);
fclose(b.infile);
if(b.buffer) free(b.buffer);
return -1;
}
af->bits = 16;
cb->totalTime = totalTime;
time = 0.0;
advanceAacBuffer(&b,bread);
while(!eof) {
fillAacBuffer(&b);
if(b.bytesIntoBuffer==0) {
eof = 1;
break;
}
sampleBuffer = faacDecDecode(decoder,&frameInfo,b.buffer,
b.bytesIntoBuffer);
if(frameInfo.error > 0) {
ERROR("error decoding AAC file: %s\n",dc->file);
ERROR("faad2 error: %s\n",
faacDecGetErrorMessage(frameInfo.error));
eof = 1;
break;
}
if(dc->start) {
af->channels = frameInfo.channels;
af->sampleRate = frameInfo.samplerate;
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
}
advanceAacBuffer(&b,frameInfo.bytesconsumed);
sampleCount = (unsigned long)(frameInfo.samples);
if(sampleCount>0) {
bitRate = frameInfo.bytesconsumed*8.0*
frameInfo.channels*frameInfo.samplerate/
frameInfo.samples/1024+0.5;
time+= (float)(frameInfo.samples)/frameInfo.channels/
frameInfo.samplerate;
}
sampleBufferLen = sampleCount*2;
while(sampleBufferLen>0) {
size_t size = sampleBufferLen>CHUNK_SIZE-chunkLen ?
CHUNK_SIZE-chunkLen:
sampleBufferLen;
while(cb->begin==cb->end && cb->wrap &&
!dc->stop && !dc->seek)
{
usleep(10000);
}
if(dc->seek) {
dc->seekError = 1;
dc->seek = 0;
}
else if(dc->stop) {
eof = 1;
break;
}
else {
sampleBufferLen-=size;
memcpy(cb->chunks+cb->end*CHUNK_SIZE+chunkLen,
sampleBuffer,size);
cb->times[cb->end] = time;
cb->bitRate[cb->end] = bitRate;
sampleBuffer+=size;
chunkLen+=size;
if(chunkLen>=CHUNK_SIZE) {
cb->chunkSize[cb->end] = CHUNK_SIZE;
++cb->end;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
chunkLen = 0;
}
}
}
} while (!eof);
faacDecClose(decoder);
fclose(b.infile);
if(b.buffer) free(b.buffer);
if(dc->start) return -1;
if(!dc->stop && !dc->seek && chunkLen>0) {
cb->chunkSize[cb->end] = chunkLen;
++cb->end;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
chunkLen = 0;
}
if(dc->seek) dc->seek = 0;
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else dc->state = DECODE_STATE_STOP;
return 0;
}
#endif /* HAVE_FAAD */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* 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
*/
#ifndef AAC_DECODE_H
#define AAC_DECODE_H
#include "../config.h"
#ifdef HAVE_FAAD
#include "playerData.h"
int getAacTotalTime(char * file);
int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
#endif /* HAVE_FAAD */
#endif
......@@ -116,7 +116,7 @@ void finishAudioDriver() {
}
int isCurrentAudioFormat(AudioFormat * audioFormat) {
if(!audio_device) return 0;
if(!audio_device || !audioFormat) return 0;
if(audio_format.bits!=audioFormat->bits ||
audio_format.sampleRate!=audioFormat->sampleRate ||
......@@ -136,13 +136,16 @@ int initAudio(AudioFormat * audioFormat) {
}
if(!audio_device) {
format.bits = audioFormat->bits;
format.rate = audioFormat->sampleRate;
if(audioFormat) {
audio_format.bits = audioFormat->bits;
audio_format.sampleRate = audioFormat->sampleRate;
audio_format.channels = audioFormat->channels;
}
format.bits = audio_format.bits;
format.rate = audio_format.sampleRate;
format.byte_format = AO_FMT_NATIVE;
format.channels = audioFormat->channels;
audio_format.bits = format.bits;
audio_format.sampleRate = format.rate;
audio_format.channels = format.channels;
format.channels = audio_format.channels;
blockSignals();
audio_device = ao_open_live(audio_ao_driver_id, &format,
......
......@@ -19,6 +19,8 @@
#ifndef AUDIO_H
#define AUDIO_H
#include "../config.h"
#include "mpd_types.h"
#include <stdio.h>
......
......@@ -18,10 +18,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_AUDIOFILE
#include "audiofile_decode.h"
#ifdef HAVE_AUDIOFILE
#include "command.h"
#include "utils.h"
#include "audio.h"
......@@ -86,7 +86,7 @@ int audiofile_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
while(!eof) {
if(dc->seek) {
cb->end = 0;
cb->end = cb->begin;
cb->wrap = 0;
current = dc->seekWhere * af->sampleRate;
afSeekFrame(af_fp, AF_DEFAULT_TRACK,current);
......@@ -104,10 +104,6 @@ int audiofile_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
if(dc->stop) break;
else if(dc->seek) continue;
#ifdef WORDS_BIGENDIAN
pcm_changeBufferEndianness(chunk,CHUNK_SIZE,
af->bits);
#endif
memcpy(cb->chunks+cb->end*CHUNK_SIZE,chunk,
CHUNK_SIZE);
cb->chunkSize[cb->end] = CHUNK_SIZE;
......
......@@ -21,11 +21,14 @@
#ifndef AUDIOFILE_DECODE_H
#define AUDIOFILE_DECODE_H
#include "../config.h"
#ifdef HAVE_AUDIOFILE
#include "playerData.h"
int audiofile_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
int audiofile_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);;
int getAudiofileTotalTime(char * file);
#endif /* HAVE_AUDIOFILE */
......
......@@ -19,6 +19,8 @@
#ifndef BUFFER_2_ARRAY_H
#define BUFFER_2_ARRAY_H
#include "../config.h"
int buffer2array(char * buffer, char *** array);
void freeArgArray(char ** array, int argArrayLength);
......
......@@ -19,6 +19,8 @@
#ifndef CHAR_CONV_H
#define CHAR_CONV_H
#include "../config.h"
int setCharSetConversion(char * to, char * from);
char * convStrDup(char * string);
......
......@@ -317,6 +317,7 @@ int handleSearch(FILE * fp, unsigned int * permission, int argArrayLength,
int handleUpdate(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
incrPlaylistVersion();
return updateMp3Directory(fp);
}
......
......@@ -19,6 +19,8 @@
#ifndef COMMAND_H
#define COMMAND_H
#include "../config.h"
#include <stdio.h>
#define COMMAND_RETURN_KILL 10
......
......@@ -64,7 +64,7 @@
#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_ALSA
#define CONF_MIXER_DEVICE_DEFAULT ""
#else
#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_NULL
#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_SOFTWARE
#define CONF_MIXER_DEVICE_DEFAULT ""
#endif
#endif
......
......@@ -19,6 +19,8 @@
#ifndef CONF_H
#define CONF_H
#include "../config.h"
#define CONF_PORT 0
#define CONF_MUSIC_DIRECTORY 1
#define CONF_PLAYLIST_DIRECTORY 2
......
......@@ -38,6 +38,10 @@
#ifdef HAVE_AUDIOFILE
#include "audiofile_decode.h"
#endif
#ifdef HAVE_FAAD
#include "mp4_decode.h"
#include "aac_decode.h"
#endif
#include <signal.h>
#include <sys/types.h>
......@@ -75,7 +79,7 @@ void stopDecode(DecoderControl * dc) {
(dc->start || dc->state==DECODE_STATE_DECODE))
{
dc->stop = 1;
while(decode_pid && *decode_pid>0 && dc->stop) usleep(10);
while(decode_pid && *decode_pid>0 && dc->stop) usleep(1000);
}
}
......@@ -108,12 +112,10 @@ int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
int waitOnDecode(PlayerControl * pc, AudioFormat * af, DecoderControl * dc,
Buffer * cb)
{
while(decode_pid && *decode_pid>0 && dc->start) usleep(10);
while(decode_pid && *decode_pid>0 && dc->start) usleep(1000);
if(dc->start || dc->error!=DECODE_ERROR_NOERROR) {
strncpy(pc->erroredFile,pc->file,MAXPATHLEN);
printf("error: %i, start: %i, decode_pid: %i\n",dc->error,
dc->start,*decode_pid);
pc->error = PLAYER_ERROR_FILE;
quitDecode(pc,dc);
return -1;
......@@ -126,12 +128,12 @@ int waitOnDecode(PlayerControl * pc, AudioFormat * af, DecoderControl * dc,
return -1;
}
pc->totalTime = cb->totalTime;
pc->elapsedTime = 0;
pc->bitRate = 0;
pc->sampleRate = af->sampleRate;
pc->bits = af->bits;
pc->channels = af->channels;
pc->totalTime = cb->totalTime;
return 0;
}
......@@ -145,21 +147,23 @@ void decodeSeek(PlayerControl * pc, AudioFormat * af, DecoderControl * dc,
strcmp(dc->file,pc->file)!=0)
{
stopDecode(dc);
cb->begin = 0;
cb->end = 0;
cb->wrap = 0;
dc->error = 0;
dc->start = 1;
dc->error = 0;
waitOnDecode(pc,af,dc,cb);
}
if(*decode_pid>0 && dc->state==DECODE_STATE_DECODE) {
dc->seekWhere = pc->seekWhere > pc->totalTime-1 ?
pc->totalTime-1 : pc->seekWhere;
dc->seekWhere = 1 > dc->seekWhere ? 1 : dc->seekWhere;
cb->begin = 0;
dc->seekWhere = pc->seekWhere > pc->totalTime-0.1 ?
pc->totalTime-0.1 :
pc->seekWhere;
dc->seekWhere = 0 > dc->seekWhere ? 0 : dc->seekWhere;
dc->seekError = 0;
dc->seek = 1;
pc->elapsedTime = dc->seekWhere;
pc->bitRate = 0;
while(*decode_pid>0 && dc->seek) usleep(10);
while(*decode_pid>0 && dc->seek) usleep(1000);
if(!dc->seekError) pc->elapsedTime = dc->seekWhere;
}
}
pc->seek = 0;
......@@ -176,8 +180,19 @@ void decodeSeek(PlayerControl * pc, AudioFormat * af, DecoderControl * dc,
} \
if(pc->pause) { \
pause = !pause; \
if(pause) pc->state = PLAYER_STATE_PAUSE; \
else pc->state = PLAYER_STATE_PLAY; \
if(pause) { \
finishAudio(); \
pc->state = PLAYER_STATE_PAUSE; \
} \
else { \
if(initAudio(NULL)<0) { \
strncpy(pc->erroredFile,pc->file,MAXPATHLEN); \
pc->error = PLAYER_ERROR_AUDIO; \
quitDecode(pc,dc); \
return; \
} \
pc->state = PLAYER_STATE_PLAY; \
} \
pc->pause = 0; \
kill(getppid(),SIGUSR1); \
} \
......@@ -198,6 +213,7 @@ void decodeSeek(PlayerControl * pc, AudioFormat * af, DecoderControl * dc,
int decoderInit(PlayerControl * pc, Buffer * cb, AudioFormat *af,
DecoderControl * dc) {
int pid;
int ret;
decode_pid = &(pc->decode_pid);
pid = fork();
......@@ -210,28 +226,37 @@ int decoderInit(PlayerControl * pc, Buffer * cb, AudioFormat *af,
switch(pc->decodeType) {
#ifdef HAVE_MAD
case DECODE_TYPE_MP3:
dc->error = mp3_decode(cb,af,dc);
ret = mp3_decode(cb,af,dc);
break;
#endif
#ifdef HAVE_FAAD
case DECODE_TYPE_AAC:
ret = aac_decode(cb,af,dc);
break;
case DECODE_TYPE_MP4:
ret = mp4_decode(cb,af,dc);
break;
#endif
#ifdef HAVE_OGG
case DECODE_TYPE_OGG:
dc->error = ogg_decode(cb,af,dc);
ret = ogg_decode(cb,af,dc);
break;
#endif
#ifdef HAVE_FLAC
case DECODE_TYPE_FLAC:
dc->error = flac_decode(cb,af,dc);
ret = flac_decode(cb,af,dc);
break;
#endif
#ifdef HAVE_AUDIOFILE
case DECODE_TYPE_AUDIOFILE:
dc->error = audiofile_decode(cb,af,dc);
ret = audiofile_decode(cb,af,dc);
break;
#endif
default:
dc->error = DECODE_ERROR_UNKTYPE;
ret = DECODE_ERROR_UNKTYPE;
}
if(dc->error!=DECODE_ERROR_NOERROR) {
if(ret<0) {
dc->error = DECODE_ERROR_FILE;
dc->start = 0;
dc->stop = 0;
dc->state = DECODE_STATE_STOP;
......@@ -287,7 +312,6 @@ void decode() {
{
/* PARENT */
char silence[CHUNK_SIZE];
int pause = 0;
int quit = 0;
int bbp = buffered_before_play;
......@@ -297,8 +321,6 @@ void decode() {
int nextChunk = -1;
int test;
memset(silence,0,CHUNK_SIZE);
if(waitOnDecode(pc,af,dc,cb)<0) return;
pc->state = PLAYER_STATE_PLAY;
......@@ -339,9 +361,7 @@ void decode() {
}
else doCrossFade = -1;
}
if(pause) {
if(playAudio(silence,CHUNK_SIZE)<0) quit = 1;
}
if(pause) usleep(10000);
else if((cb->begin!=cb->end || cb->wrap) &&
cb->begin!=cb->next)
{
......@@ -435,7 +455,7 @@ void decode() {
quitDecode(pc,dc);
return;
}
usleep(10);
usleep(1000);
}
if(pc->queueState!=PLAYER_QUEUE_PLAY) {
quit = 1;
......
......@@ -19,6 +19,10 @@
#ifndef DECODE_H
#define DECODE_H
#include "../config.h"
#include "mpd_types.h"
#include <stdio.h>
#include <sys/param.h>
......@@ -26,19 +30,23 @@
#define DECODE_TYPE_OGG 1
#define DECODE_TYPE_FLAC 2
#define DECODE_TYPE_AUDIOFILE 3
#define DECODE_TYPE_MP4 4
#define DECODE_TYPE_AAC 5
#define DECODE_STATE_STOP 0
#define DECODE_STATE_DECODE 1
#define DECODE_ERROR_NOERROR 0
#define DECODE_ERROR_UNKTYPE 1
#define DECODE_ERROR_FILE 2
typedef struct _DecoderControl {
int state;
int stop;
int start;
int error;
int seek;
mpd_sint8 state;
mpd_sint8 stop;
mpd_sint8 start;
mpd_uint16 error;
mpd_sint8 seek;
mpd_sint8 seekError;
double seekWhere;
char file[MAXPATHLEN+1];
} DecoderControl;
......
......@@ -20,13 +20,12 @@
#include "ls.h"
#include "command.h"
#include "tables.h"
#include "utils.h"
#include "path.h"
#include "log.h"
#include "playlist.h"
#include "conf.h"
#include "stats.h"
#include "playlist.h"
#include <string.h>
#include <sys/types.h>
......@@ -76,6 +75,8 @@ int exploreDirectory(Directory * directory);
int updateDirectory(Directory * directory);
void deleteEmptyDirectoriesInDirectory(Directory * directory);
int addSubDirectoryToDirectory(Directory * directory, char * shortname, char * name);
Directory * newDirectory(Directory * parentDirectory, char * dirname, time_t mtime) {
......@@ -88,7 +89,7 @@ Directory * newDirectory(Directory * parentDirectory, char * dirname, time_t mti
directory->parentDirectory = parentDirectory;
directory->subDirectories = newDirectoryList();
directory->songs = newSongList();
if(mtime<0) directory->mtime = isDir(dirname);
if(mtime<0) isDir(dirname,&(directory->mtime));
else directory->mtime = mtime;
return directory;
......@@ -96,8 +97,6 @@ Directory * newDirectory(Directory * parentDirectory, char * dirname, time_t mti
void freeDirectory(Directory * directory) {
freeDirectoryList(directory->subDirectories);
removeSongsFromTables(directory->songs);
deleteSongsFromPlaylist(directory->songs);
freeSongList(directory->songs);
if(directory->utf8name) free(directory->utf8name);
free(directory);
......@@ -113,30 +112,48 @@ void freeDirectoryList(DirectoryList * directoryList) {
void removeSongFromDirectory(Directory * directory, char * shortname) {
void * song;
if(findInList(directory->songs,shortname,&song)) {
removeASongFromTables((Song *)song);
deleteASongFromPlaylist((Song *)song);
LOG("removing: %s\n",((Song *)song)->utf8file);
deleteFromList(directory->songs,shortname);
}
}
void deleteEmptyDirectoriesInDirectory(Directory * directory) {
ListNode * node = directory->subDirectories->firstNode;
ListNode * nextNode;
Directory * subDir;
while(node) {
subDir = (Directory *)node->data;
deleteEmptyDirectoriesInDirectory(subDir);
nextNode = node->nextNode;
if(subDir->subDirectories->numberOfNodes==0 &&
subDir->songs->numberOfNodes==0)
{
deleteNodeFromList(directory->subDirectories,node);
}
node = nextNode;
}
}
int updateInDirectory(Directory * directory, char * shortname, char * name) {
time_t mtime;
void * song;
void * subDir;
if((mtime = isMusic(name))) {
if(isMusic(name,&mtime)) {
if(0==findInList(directory->songs,shortname,&song)) {
LOG("adding %s\n",name);
addToDirectory(directory,shortname,name);
}
else if(mtime>((Song *)song)->mtime) {
else if(mtime!=((Song *)song)->mtime) {
LOG("updating %s\n",name);
updateSongInfo((Song *)song);
if(updateSongInfo((Song *)song)<0) {
removeSongFromDirectory(directory,shortname);
}
}
}
else if((mtime = isDir(name))) {
else if(isDir(name,&mtime)) {
if(findInList(directory->subDirectories,shortname,(void **)&subDir)) {
updateDirectory((Directory *)subDir);
}
......@@ -184,11 +201,13 @@ int removeDeletedFromDirectory(Directory * directory) {
while(node) {
tmpNode = node->nextNode;
if(findInList(entList,node->key,&name)) {
if(!isDir((char *)name)) {
if(!isDir((char *)name,NULL)) {
LOG("removing directory: %s\n",(char*)name);
deleteFromList(directory->subDirectories,node->key);
}
}
else {
LOG("removing directory: %s\n",(char*)name);
deleteFromList(directory->subDirectories,node->key);
}
node = tmpNode;
......@@ -198,7 +217,7 @@ int removeDeletedFromDirectory(Directory * directory) {
while(node) {
tmpNode = node->nextNode;
if(findInList(entList,node->key,(void **)&name)) {
if(!isMusic(name)) {
if(!isMusic(name,NULL)) {
removeSongFromDirectory(directory,node->key);
}
}
......@@ -246,7 +265,7 @@ int updateDirectory(Directory * directory) {
closedir(dir);
if(directory->utf8name) directory->mtime = isDir(directory->utf8name);
if(directory->utf8name) isDir(directory->utf8name,&(directory->mtime));
return 0;
}
......@@ -266,7 +285,7 @@ int exploreDirectory(Directory * directory) {
DEBUG("explore: attempting to opendir: %s\n",dirname);
if((dir = opendir(rmp2amp(utf8ToFsCharset(dirname))))==NULL) return -1;
LOG("explore: %s\n",dirname);
DEBUG("explore: %s\n",dirname);
while((ent = readdir(dir))) {
if(ent->d_name[0]=='.') continue; /* hide hidden stuff */
......@@ -301,14 +320,14 @@ int addSubDirectoryToDirectory(Directory * directory, char * shortname,
}
int addToDirectory(Directory * directory, char * shortname, char * name) {
if(isDir(name)) {
if(isDir(name,NULL)) {
return addSubDirectoryToDirectory(directory,shortname,name);
}
else if(isMusic(name)) {
else if(isMusic(name,NULL)) {
Song * song;
song = addSongToList(directory->songs,shortname,name);
if(!song) return -1;
addSongToTables(song);
LOG("added %s\n",name);
return 0;
}
......@@ -475,6 +494,7 @@ void sortDirectory(Directory * directory) {
int writeDirectoryDB() {
FILE * fp;
deleteEmptyDirectoriesInDirectory(mp3rootDirectory);
sortDirectory(mp3rootDirectory);
stats.numberOfSongs = countSongsIn(stderr,NULL);
stats.dbPlayTime = sumSongTimesIn(stderr,NULL);
......@@ -528,7 +548,8 @@ int readDirectoryDB() {
else if(0==strncmp(DIRECTORY_FS_CHARSET,buffer,
strlen(DIRECTORY_FS_CHARSET)))
{
char * fsCharset;
char * fsCharset;
char * tempCharset;
if(foundFsCharset) {
ERROR("already found "
......@@ -540,23 +561,23 @@ int readDirectoryDB() {
fsCharset = &(buffer[strlen(
DIRECTORY_FS_CHARSET)]);
if(getConf()[CONF_FS_CHARSET] &&
strcmp(fsCharset,
getFsCharset()))
if((tempCharset =
getConf()[CONF_FS_CHARSET]) &&
strcmp(fsCharset,tempCharset))
{
ERROR("Using \"%s\" for the "
"filesystem charset "
"instead of \"%s\"\n",
fsCharset,
getFsCharset());
fsCharset,tempCharset);
ERROR("maybe you need to "
"recreate the db?\n");
setFsCharset(fsCharset);
}
}
else {
ERROR("unknown line in db info: %s\n",
ERROR("directory: unknown line in db info: %s\n",
buffer);
exit(-1);
}
}
}
......
......@@ -19,6 +19,8 @@
#ifndef DIRECTORY_H
#define DIRECTORY_H
#include "../config.h"
#include "song.h"
#include <stdio.h>
......
......@@ -16,9 +16,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_FLAC
#include "flac_decode.h"
#ifdef HAVE_FLAC
#include "utils.h"
#include "log.h"
#include "pcm_utils.h"
......@@ -103,7 +104,7 @@ void flacPlayFile(char *file, Buffer * cb, AudioFormat * af,
if(dc->seek) {
FLAC__uint64 sampleToSeek = dc->seekWhere*
af->sampleRate+0.5;
cb->end = 0;
cb->end = cb->begin;
cb->wrap = 0;
if(FLAC__file_decoder_seek_absolute(flacDec,
sampleToSeek))
......@@ -187,9 +188,6 @@ int flacSendChunk(FlacData * data) {
if(data->dc->stop) return -1;
if(data->dc->seek) return 0;
#ifdef WORDS_BIGENDIAN
pcm_changeBufferEndianness(chunk,CHUNK_SIZE,data->af->bits);
#endif
memcpy(data->cb->chunks+data->cb->end*CHUNK_SIZE,data->chunk,
CHUNK_SIZE);
data->cb->chunkSize[data->cb->end] = data->chunk_length;
......@@ -282,6 +280,15 @@ int flac_getAudioFormatAndTime(char * file, AudioFormat * format, float * time)
return ret;
}
int getFlacTotalTime(char * file) {
float totalTime;
AudioFormat af;
if(flac_getAudioFormatAndTime(file,&af,&totalTime)<0) return -1;
return (int)(totalTime+0.5);
}
int flac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
if(flac_getAudioFormatAndTime(dc->file,af,&(cb->totalTime))<0) {
ERROR("\"%s\" doesn't seem to be a flac\n",dc->file);
......
......@@ -19,10 +19,14 @@
#ifndef FLAC_DECODE_H
#define FLAC_DECODE_H
#include "../config.h"
#include "playerData.h"
#include <stdio.h>
int flac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
int getFlacTotalTime(char * file);
#endif
......@@ -19,6 +19,8 @@
#ifndef INTERFACE_H
#define INTERFACE_H
#include "../config.h"
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
......
......@@ -21,6 +21,8 @@
## Process this file with automake to produce Makefile.in
AUTOMAKE_OPTIONS = foreign 1.6
SUBDIRS =
#DIST_SUBDIRS = msvc++
......
......@@ -72,8 +72,6 @@
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* Define as `__inline' if that's what the C compiler calls it, or to nothing
if it is not supported. */
#undef inline
#endif
......@@ -21,6 +21,8 @@
## Process this file with automake to produce Makefile.in
AUTOMAKE_OPTIONS = foreign 1.6
SUBDIRS =
#DIST_SUBDIRS = msvc++
......
......@@ -125,11 +125,9 @@
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* Define as `__inline' if that's what the C compiler calls it, or to nothing
if it is not supported. */
#undef inline
#endif
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -24,12 +24,12 @@
extern "C" {
# endif
# define FPM_DEFAULT
# define FPM_INTEL
# define SIZEOF_INT 4
# define SIZEOF_LONG 8
# define SIZEOF_LONG 4
# define SIZEOF_LONG_LONG 8
......
......@@ -20,6 +20,8 @@
#ifndef LIST_H
#define LIST_H
#include "../config.h"
#include <stdlib.h>
/* used to make a list where free() will be used to free data in list */
......
......@@ -19,6 +19,8 @@
#ifndef LISTEN_H
#define LISTEN_H
#include "../config.h"
extern int listenSocket;
int establish(unsigned short port);
......
......@@ -19,6 +19,8 @@
#ifndef LOG_H
#define LOG_H
#include "../config.h"
#include "myfprintf.h"
#define LOG_LEVEL_LOW 0
......
......@@ -110,172 +110,111 @@ int lsPlaylists(FILE * fp, char * utf8path) {
return 0;
}
time_t isMusic(char * utf8file) {
time_t ret = 0;
#ifdef HAVE_OGG
if((ret = isOgg(utf8file))) return ret;
#endif
#ifdef HAVE_FLAC
if((ret = isFlac(utf8file))) return ret;
#endif
#ifdef HAVE_MAD
if((ret = isMp3(utf8file))) return ret;
#endif
#ifdef HAVE_AUDIOFILE
if((ret = isWave(utf8file))) return ret;
#endif
return ret;
}
time_t isPlaylist(char * utf8file) {
int isFile(char * utf8file, time_t * mtime) {
struct stat st;
char * file = utf8ToFsCharset(utf8file);
char * actualFile = file;
char * temp = NULL;
if(actualFile[0]!='/') actualFile = rpp2app(file);
if(actualFile[0]!='/') actualFile = rmp2amp(file);
if(stat(actualFile,&st)==0) {
if(S_ISREG(st.st_mode)) {
char * dup;
char * cLast;
char * cNext;
int ret = 0;
dup = strdup(file);
cNext = cLast = strtok(dup,".");
while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcmp(cLast,PLAYLIST_FILE_SUFFIX)) {
ret = st.st_mtime;
}
free(dup);
if(temp) free(temp);
return ret;
if(mtime) *mtime = st.st_mtime;
return 1;
}
else return 0;
}
if(temp) free(temp);
return 0;
}
time_t isWave(char * utf8file) {
struct stat st;
int hasSuffix(char * utf8file, char * suffix) {
char * file = utf8ToFsCharset(utf8file);
char * actualFile = file;
char * dup = strdup(file);
char * cLast;
char * cNext;
int ret = 0;
cNext = cLast = strtok(dup,".");
if(actualFile[0]!='/') actualFile = rmp2amp(file);
while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcasecmp(cLast,suffix)) ret = 1;
free(dup);
if(stat(actualFile,&st)==0) {
if(S_ISREG(st.st_mode)) {
char * dup;
char * cLast;
char * cNext;
time_t ret = 0;
dup = strdup(file);
cNext = cLast = strtok(dup,".");
while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcasecmp(cLast,"wav")) {
ret = st.st_mtime;
}
free(dup);
return ret;
}
else return 0;
}
return ret;
}
int isPlaylist(char * utf8file) {
if(isFile(utf8file,NULL)) {
return hasSuffix(utf8file,PLAYLIST_FILE_SUFFIX);
}
return 0;
}
time_t isFlac(char * utf8file) {
struct stat st;
char * file = utf8ToFsCharset(utf8file);
char * actualFile = file;
int hasWaveSuffix(char * utf8file) {
return hasSuffix(utf8file,"wav");
}
if(actualFile[0]!='/') actualFile = rmp2amp(file);
int isWave(char * utf8file, time_t * mtime) {
if(isFile(utf8file,mtime)) return hasWaveSuffix(utf8file);
return 0;
}
if(stat(actualFile,&st)==0) {
if(S_ISREG(st.st_mode)) {
char * dup;
char * cLast;
char * cNext;
time_t ret = 0;
dup = strdup(file);
cNext = cLast = strtok(dup,".");
while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcasecmp(cLast,"flac")) {
ret = st.st_mtime;
}
free(dup);
return ret;
}
else return 0;
}
int hasFlacSuffix(char * utf8file) {
return hasSuffix(utf8file,"flac");
}
int isFlac(char * utf8file, time_t * mtime) {
if(isFile(utf8file,mtime)) return hasFlacSuffix(utf8file);
return 0;
}
time_t isOgg(char * utf8file) {
struct stat st;
char * file = utf8ToFsCharset(utf8file);
char * actualFile = file;
int hasOggSuffix(char * utf8file) {
return hasSuffix(utf8file,"ogg");
}
if(actualFile[0]!='/') actualFile = rmp2amp(file);
int isOgg(char * utf8file, time_t * mtime) {
if(isFile(utf8file,mtime)) return hasOggSuffix(utf8file);
return 0;
}
if(stat(actualFile,&st)==0) {
if(S_ISREG(st.st_mode)) {
char * dup;
char * cLast;
char * cNext;
time_t ret = 0;
dup = strdup(file);
cNext = cLast = strtok(dup,".");
while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcasecmp(cLast,"ogg")) {
ret = st.st_mtime;
}
free(dup);
return ret;
}
else return 0;
}
int hasAacSuffix(char * utf8file) {
return hasSuffix(utf8file,"aac");
}
int isAac(char * utf8file, time_t * mtime) {
if(isFile(utf8file,mtime)) return hasAacSuffix(utf8file);
return 0;
}
time_t isMp3(char * utf8file) {
struct stat st;
char * file = utf8ToFsCharset(utf8file);
char * actualFile = file;
int hasMp4Suffix(char * utf8file) {
if(hasSuffix(utf8file,"mp4")) return 1;
if(hasSuffix(utf8file,"m4a")) return 1;
return 0;
}
if(actualFile[0]!='/') actualFile = rmp2amp(file);
int isMp4(char * utf8file, time_t * mtime) {
if(isFile(utf8file,mtime)) return hasMp4Suffix(utf8file);
return 0;
}
if(stat(actualFile,&st)==0) {
if(S_ISREG(st.st_mode)) {
char * dup;
char * cLast;
char * cNext;
time_t ret = 0;
dup = strdup(file);
cNext = cLast = strtok(dup,".");
while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcasecmp(cLast,"mp3")) {
ret = st.st_mtime;
}
free(dup);
return ret;
}
else return 0;
}
int hasMp3Suffix(char * utf8file) {
return hasSuffix(utf8file,"mp3");
}
int isMp3(char * utf8file, time_t * mtime) {
if(isFile(utf8file,mtime)) return hasMp3Suffix(utf8file);
return 0;
}
time_t isDir(char * utf8name) {
int isDir(char * utf8name, time_t * mtime) {
struct stat st;
if(stat(rmp2amp(utf8ToFsCharset(utf8name)),&st)==0) {
if(S_ISDIR(st.st_mode)) return st.st_mtime;
if(S_ISDIR(st.st_mode)) {
if(mtime) *mtime = st.st_mtime;
return 1;
}
}
else {
DEBUG("isDir: unable to stat: %s (%s)\n",utf8name,
......@@ -284,3 +223,27 @@ time_t isDir(char * utf8name) {
return 0;
}
int isMusic(char * utf8file, time_t * mtime) {
if(isFile(utf8file,mtime)) {
#ifdef HAVE_OGG
if(hasOggSuffix(utf8file)) return 1;
#endif
#ifdef HAVE_FLAC
if(hasFlacSuffix(utf8file)) return 1;
#endif
#ifdef HAVE_MAD
if(hasMp3Suffix(utf8file)) return 1;
#endif
#ifdef HAVE_AUDIOFILE
if(hasWaveSuffix(utf8file)) return 1;
#endif
#ifdef HAVE_FAAD
if(hasMp4Suffix(utf8file)) return 1;
if(hasAacSuffix(utf8file)) return 1;
#endif
}
return 0;
}
......@@ -19,24 +19,30 @@
#ifndef LS_H
#define LS_H
#include "../config.h"
#include <stdio.h>
#include <time.h>
int lsPlaylists(FILE * fp, char * utf8path);
time_t isMp3(char * utf8file);
int isMp3(char * utf8file, time_t * mtime);
int isAac(char * utf8file, time_t * mtime);
int isMp4(char * utf8file, time_t * mtime);
time_t isOgg(char * utf8file);
int isOgg(char * utf8file, time_t * mtime);
time_t isFlac(char * utf8file);
int isFlac(char * utf8file, time_t * mtime);
time_t isWave(char * utf8file);
int isWave(char * utf8file, time_t * mtime);
time_t isMusic(char * utf8file);
int isMusic(char * utf8file, time_t * mtime);
time_t isDir(char * utf8name);
int isDir(char * utf8name, time_t * mtime);
time_t isPlaylist(char * utf8file);
int isPlaylist(char * utf8file);
char * dupAndStripPlaylistSuffix(char * file);
......
......@@ -69,12 +69,12 @@ void usage(char * argv[]) {
SYSTEM_CONFIG_FILE_LOCATION);
ERROR("\n");
ERROR("options:\n");
ERROR(" --help this usage statement\n");
ERROR(" --no-daemon don't detach from console\n");
ERROR(" --create-db force (re)creation database\n");
ERROR(" --no-create-db don't create database\n");
ERROR(" --verbose verbose logging\n");
ERROR(" --version prints version information\n");
ERROR(" --help this usage statement\n");
ERROR(" --no-daemon don't detach from console\n");
ERROR(" --create-db force (re)creation database\n");
ERROR(" --no-create-db don't create database\n");
ERROR(" --verbose verbose logging\n");
ERROR(" --version prints version information\n");
}
void version() {
......@@ -329,6 +329,7 @@ int main(int argc, char * argv[]) {
}
initTables();
initPlaylist();
if(!options.dbFile) {
strncpy(directorydb,playlistDir,MAXPATHLEN);
......@@ -353,7 +354,6 @@ int main(int argc, char * argv[]) {
initPlayerData();
initVolume();
initInterfaces();
initPlaylist();
close(STDIN_FILENO);
if(options.daemon) {
......
......@@ -16,9 +16,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "mp3_decode.h"
#ifdef HAVE_MAD
#include "mp3_decode.h"
#include "pcm_utils.h"
#ifdef USE_MPD_MAD
#include "libmad/mad.h"
......@@ -375,7 +376,7 @@ int getMp3TotalTime(char * file) {
initMp3DecodeData(&data);
if(decodeFirstFrame(&data)<0) ret = -1;
else ret = data.totalTime;
else ret = data.totalTime+0.5;
mp3DecodeDataFinalize(&data);
return ret;
......@@ -403,12 +404,9 @@ int mp3ChildSendData(mp3DecodeData * data, Buffer * cb, DecoderControl * dc) {
if(dc->seek) return 0;
/* be sure to remove this! */
#ifdef WORDS_BIGENDIAN
pcm_changeBufferEndianness(data->outputBuffer,CHUNK_SIZE,16);
#endif
memcpy(cb->chunks+cb->end*CHUNK_SIZE,data->outputBuffer,CHUNK_SIZE);
cb->chunkSize[cb->end] = data->outputPtr-data->outputBuffer;
cb->bitRate[cb->end] = data->bitRate/1000;
cb->bitRate[cb->end] = data->bitRate/1024;
cb->times[cb->end] = data->elapsedTime;
cb->end++;
......@@ -460,16 +458,20 @@ int mp3Read(mp3DecodeData * data, Buffer * cb, DecoderControl * dc) {
mad_synth_frame(&data->synth,&data->frame);
for(i=0;i<(data->synth).pcm.length;i++) {
signed int sample;
sample = (signed int) audio_linear_dither(16,(data->synth).pcm.samples[0][i],&dither);
*(data->outputPtr++) = sample&0xff;
*(data->outputPtr++) = sample>>8;
mpd_sint16 * sample;
sample = (mpd_sint16 *)data->outputPtr;
*sample = (mpd_sint16) audio_linear_dither(16,
(data->synth).pcm.samples[0][i],
&dither);
data->outputPtr+=2;
if(MAD_NCHANNELS(&(data->frame).header)==2) {
sample = (signed int) audio_linear_dither(16,(data->synth).pcm.samples[1][i],&dither);
*(data->outputPtr++) = sample&0xff;
*(data->outputPtr++) = sample>>8;
sample = (mpd_sint16 *)data->outputPtr;
*sample = (mpd_sint16) audio_linear_dither(16,
(data->synth).pcm.samples[1][i],
&dither);
data->outputPtr+=2;
}
if(data->outputPtr==data->outputBufferEnd) {
......@@ -485,7 +487,7 @@ int mp3Read(mp3DecodeData * data, Buffer * cb, DecoderControl * dc) {
if(dc->seek) {
long i = 0;
cb->wrap = 0;
cb->end = 0;
cb->end = cb->begin;
data->muteFrame = 1;
while(i<data->highestFrame && dc->seekWhere >
((float)mad_timer_count(data->times[i],
......
......@@ -19,6 +19,8 @@
#ifndef MP3_DECODE_H
#define MP3_DECODE_H
#include "../config.h"
#ifdef HAVE_MAD
#include "playerData.h"
......
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* 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 "mp4_decode.h"
#ifdef HAVE_FAAD
#include "command.h"
#include "utils.h"
#include "audio.h"
#include "log.h"
#include "pcm_utils.h"
#include "mp4ff/mp4ff.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <faad.h>
/* all code here is either based on or copied from FAAD2's frontend code */
int mp4_getAACTrack(mp4ff_t *infile) {
/* find AAC track */
int i, rc;
int numTracks = mp4ff_total_tracks(infile);
for (i = 0; i < numTracks; i++) {
unsigned char *buff = NULL;
int buff_size = 0;
mp4AudioSpecificConfig mp4ASC;
mp4ff_get_decoder_config(infile, i, &buff, &buff_size);
if (buff) {
rc = AudioSpecificConfig(buff, buff_size, &mp4ASC);
free(buff);
if (rc < 0) continue;
return i;
}
}
/* can't decode this */
return -1;
}
uint32_t mp4_readCallback(void *user_data, void *buffer, uint32_t length) {
return fread(buffer, 1, length, (FILE*)user_data);
}
uint32_t mp4_seekCallback(void *user_data, uint64_t position) {
return fseek((FILE*)user_data, position, SEEK_SET);
}
int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
FILE * fh;
mp4ff_t * mp4fh;
mp4ff_callback_t * mp4cb;
int32_t track;
float time;
int32_t scale;
faacDecHandle decoder;
faacDecFrameInfo frameInfo;
faacDecConfigurationPtr config;
unsigned char * mp4Buffer;
int mp4BufferSize;
unsigned long sampleRate;
unsigned char channels;
long sampleId;
long numSamples;
int eof = 0;
long dur;
unsigned int sampleCount;
char * sampleBuffer;
size_t sampleBufferLen;
unsigned int initial = 1;
int chunkLen = 0;
float * seekTable;
long seekTableEnd = -1;
int seekPositionFound = 0;
long offset;
mpd_uint16 bitRate = 0;
fh = fopen(dc->file,"r");
if(!fh) {
ERROR("failed to open %s\n",dc->file);
return -1;
}
mp4cb = malloc(sizeof(mp4ff_callback_t));
mp4cb->read = mp4_readCallback;
mp4cb->seek = mp4_seekCallback;
mp4cb->user_data = fh;
mp4fh = mp4ff_open_read(mp4cb);
if(!mp4fh) {
ERROR("Input does not appear to be a mp4 stream.\n");
free(mp4cb);
fclose(fh);
return -1;
}
track = mp4_getAACTrack(mp4fh);
if(track < 0) {
ERROR("No AAC track found in mp4 stream.\n");
mp4ff_close(mp4fh);
fclose(fh);
free(mp4cb);
return -1;
}
decoder = faacDecOpen();
config = faacDecGetCurrentConfiguration(decoder);
config->outputFormat = FAAD_FMT_16BIT;
#ifdef HAVE_FAACDECCONFIGURATION_DOWNMATRIX
config->downMatrix = 1;
#endif
#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
config->dontUpSampleImplicitSBR = 0;
#endif
faacDecSetConfiguration(decoder,config);
af->bits = 16;
mp4Buffer = NULL;
mp4BufferSize = 0;
mp4ff_get_decoder_config(mp4fh,track,&mp4Buffer,&mp4BufferSize);
if(faacDecInit2(decoder,mp4Buffer,mp4BufferSize,&sampleRate,&channels)
< 0)
{
ERROR("Error not a AAC stream.\n");
faacDecClose(decoder);
mp4ff_close(mp4fh);
free(mp4cb);
fclose(fh);
return -1;
}
af->sampleRate = sampleRate;
af->channels = channels;
time = mp4ff_get_track_duration_use_offsets(mp4fh,track);
scale = mp4ff_time_scale(mp4fh,track);
if(mp4Buffer) free(mp4Buffer);
if(scale < 0) {
ERROR("Error getting audio format of mp4 AAC track.\n");
faacDecClose(decoder);
mp4ff_close(mp4fh);
fclose(fh);
free(mp4cb);
return -1;
}
cb->totalTime = ((float)time)/scale;
numSamples = mp4ff_num_samples(mp4fh,track);
time = 0.0;
seekTable = malloc(sizeof(float)*numSamples);
for(sampleId=0; sampleId<numSamples && !eof; sampleId++) {
if(dc->seek && seekTableEnd>1 &&
seekTable[seekTableEnd]>=dc->seekWhere)
{
int i = 2;
while(seekTable[i]<dc->seekWhere) i++;
sampleId = i-1;
time = seekTable[sampleId];
}
dur = mp4ff_get_sample_duration(mp4fh,track,sampleId);
offset = mp4ff_get_sample_offset(mp4fh,track,sampleId);
if(sampleId>seekTableEnd) {
seekTable[sampleId] = time;
seekTableEnd = sampleId;
}
if(sampleId==0) dur = 0;
if(offset>dur) dur = 0;
else dur-=offset;
time+=((float)dur)/scale;
if(dc->seek && time>dc->seekWhere) seekPositionFound = 1;
if(dc->seek && seekPositionFound) {
seekPositionFound = 0;
chunkLen = 0;
cb->end = cb->begin;
cb->wrap = 0;
dc->seek = 0;
}
if(dc->seek) continue;
if(mp4ff_read_sample(mp4fh,track,sampleId,&mp4Buffer,
&mp4BufferSize) == 0)
{
eof = 1;
continue;
}
sampleBuffer = faacDecDecode(decoder,&frameInfo,mp4Buffer,
mp4BufferSize);
if(mp4Buffer) free(mp4Buffer);
if(frameInfo.error > 0) {
ERROR("error decoding MP4 file: %s\n",dc->file);
ERROR("faad2 error: %s\n",
faacDecGetErrorMessage(frameInfo.error));
eof = 1;
break;
}
if(dc->start) {
channels = frameInfo.channels;
scale = frameInfo.samplerate;
af->channels = frameInfo.channels;
af->sampleRate = frameInfo.samplerate;
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
}
if(channels*(dur+offset) > frameInfo.samples) {
dur = frameInfo.samples/channels;
offset = 0;
}
sampleCount = (unsigned long)(dur*channels);
if(sampleCount>0) {
initial =0;
bitRate = frameInfo.bytesconsumed*8.0*
frameInfo.channels*scale/
frameInfo.samples/1024+0.5;
}
sampleBufferLen = sampleCount*2;
sampleBuffer+=offset*channels*2;
while(sampleBufferLen>0 && !dc->seek) {
size_t size = sampleBufferLen>CHUNK_SIZE-chunkLen ?
CHUNK_SIZE-chunkLen:
sampleBufferLen;
while(cb->begin==cb->end && cb->wrap &&
!dc->stop && !dc->seek)
{
usleep(10000);
}
if(dc->stop) {
eof = 1;
break;
}
else if(!dc->seek) {
sampleBufferLen-=size;
memcpy(cb->chunks+cb->end*CHUNK_SIZE+chunkLen,
sampleBuffer,size);
cb->times[cb->end] = time;
cb->bitRate[cb->end] = bitRate;
sampleBuffer+=size;
chunkLen+=size;
if(chunkLen>=CHUNK_SIZE) {
cb->chunkSize[cb->end] = CHUNK_SIZE;
++cb->end;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
chunkLen = 0;
}
}
}
}
free(seekTable);
faacDecClose(decoder);
mp4ff_close(mp4fh);
fclose(fh);
free(mp4cb);
if(dc->start) return -1;
if(!dc->stop && !dc->seek && chunkLen>0) {
cb->chunkSize[cb->end] = chunkLen;
++cb->end;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
chunkLen = 0;
}
if(dc->seek) dc->seek = 0;
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else dc->state = DECODE_STATE_STOP;
return 0;
}
#endif /* HAVE_FAAD */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* 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
*/
#ifndef MP4_DECODE_H
#define MP4_DECODE_H
#include "../config.h"
#ifdef HAVE_FAAD
#include "playerData.h"
#include "mp4ff/mp4ff.h"
int mp4_getAACTrack(mp4ff_t *infile);
uint32_t mp4_readCallback(void *user_data, void *buffer, uint32_t length);
uint32_t mp4_seekCallback(void *user_data, uint64_t position);
int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
#endif /* HAVE_FAAD */
#endif
noinst_LTLIBRARIES = libmp4ff.la
noinst_HEADERS = mp4ff.h
libmp4ff_la_SOURCES = mp4ff.c mp4atom.c mp4meta.c mp4sample.c mp4util.c \
mp4tagupdate.c mp4ff.h mp4ffint.h mp4ff_int_types.h \
drms.h drms.c drmstables.h
AM_CFLAGS = -DUSE_TAGGING=1
/*****************************************************************************
* drms.h : DRMS
*****************************************************************************
* Copyright (C) 2004 VideoLAN
* $Id: drms.h,v 1.3 2004/01/11 15:52:18 menno Exp $
*
* Author: Jon Lech Johansen <jon-vl@nanocrew.net>
*
* 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, USA.
*****************************************************************************/
#define DRMS_INIT_UKEY 0
#define DRMS_INIT_IVIV 1
#define DRMS_INIT_NAME 2
#define DRMS_INIT_PRIV 3
extern int drms_get_sys_key( uint32_t *p_sys_key );
extern int drms_get_user_key( uint32_t *p_sys_key,
uint32_t *p_user_key );
extern void *drms_alloc();
extern void drms_free( void *p_drms );
extern int drms_init( void *p_drms, uint32_t i_type,
uint8_t *p_info, uint32_t i_len );
extern void drms_decrypt( void *p_drms, uint32_t *p_buffer,
uint32_t i_len );
/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003-2004 M. Bakker, Ahead Software AG, http://www.nero.com
**
** 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.
**
** Any non-GPL usage of this software or parts of this software is strictly
** forbidden.
**
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
** $Id: mp4ff.h,v 1.19 2004/01/11 15:52:18 menno Exp $
**/
#ifndef MP4FF_H
#define MP4FF_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include "mp4ff_int_types.h"
/* file callback structure */
typedef struct
{
uint32_t (*read)(void *user_data, void *buffer, uint32_t length);
uint32_t (*write)(void *udata, void *buffer, uint32_t length);
uint32_t (*seek)(void *user_data, uint64_t position);
uint32_t (*truncate)(void *user_data);
void *user_data;
} mp4ff_callback_t;
/* mp4 main file structure */
typedef void* mp4ff_t;
/* API */
mp4ff_t *mp4ff_open_read(mp4ff_callback_t *f);
void mp4ff_close(mp4ff_t *f);
int32_t mp4ff_get_sample_duration(const mp4ff_t *f, const int32_t track, const int32_t sample);
int32_t mp4ff_get_sample_duration_use_offsets(const mp4ff_t *f, const int32_t track, const int32_t sample);
int64_t mp4ff_get_sample_position(const mp4ff_t *f, const int32_t track, const int32_t sample);
int32_t mp4ff_get_sample_offset(const mp4ff_t *f, const int32_t track, const int32_t sample);
int32_t mp4ff_find_sample(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip);
int32_t mp4ff_find_sample_use_offsets(const mp4ff_t *f, const int32_t track, const int64_t offset,int32_t * toskip);
int32_t mp4ff_read_sample(mp4ff_t *f, const int track, const int sample,
unsigned char **audio_buffer, unsigned int *bytes);
int32_t mp4ff_read_sample_v2(mp4ff_t *f, const int track, const int sample,unsigned char *buffer);//returns 0 on error, number of bytes read on success, use mp4ff_read_sample_getsize() to check buffer size needed
int32_t mp4ff_read_sample_getsize(mp4ff_t *f, const int track, const int sample);//returns 0 on error, buffer size needed for mp4ff_read_sample_v2() on success
int32_t mp4ff_get_decoder_config(const mp4ff_t *f, const int track,
unsigned char** ppBuf, unsigned int* pBufSize);
int32_t mp4ff_get_track_type(const mp4ff_t *f, const int track);
int32_t mp4ff_total_tracks(const mp4ff_t *f);
int32_t mp4ff_num_samples(const mp4ff_t *f, const int track);
int32_t mp4ff_time_scale(const mp4ff_t *f, const int track);
uint32_t mp4ff_get_avg_bitrate(const mp4ff_t *f, const int32_t track);
uint32_t mp4ff_get_max_bitrate(const mp4ff_t *f, const int32_t track);
int64_t mp4ff_get_track_duration(const mp4ff_t *f, const int32_t track); //returns (-1) if unknown
int64_t mp4ff_get_track_duration_use_offsets(const mp4ff_t *f, const int32_t track); //returns (-1) if unknown
uint32_t mp4ff_get_sample_rate(const mp4ff_t *f, const int32_t track);
uint32_t mp4ff_get_channel_count(const mp4ff_t * f,const int32_t track);
uint32_t mp4ff_get_audio_type(const mp4ff_t * f,const int32_t track);
/* metadata */
int mp4ff_meta_get_num_items(const mp4ff_t *f);
int mp4ff_meta_get_by_index(const mp4ff_t *f, unsigned int index,
char **item, char **value);
int mp4ff_meta_get_title(const mp4ff_t *f, char **value);
int mp4ff_meta_get_artist(const mp4ff_t *f, char **value);
int mp4ff_meta_get_writer(const mp4ff_t *f, char **value);
int mp4ff_meta_get_album(const mp4ff_t *f, char **value);
int mp4ff_meta_get_date(const mp4ff_t *f, char **value);
int mp4ff_meta_get_tool(const mp4ff_t *f, char **value);
int mp4ff_meta_get_comment(const mp4ff_t *f, char **value);
int mp4ff_meta_get_genre(const mp4ff_t *f, char **value);
int mp4ff_meta_get_track(const mp4ff_t *f, char **value);
int mp4ff_meta_get_disc(const mp4ff_t *f, char **value);
int mp4ff_meta_get_compilation(const mp4ff_t *f, char **value);
int mp4ff_meta_get_tempo(const mp4ff_t *f, char **value);
int32_t mp4ff_meta_get_coverart(const mp4ff_t *f, char **value);
#ifdef USE_TAGGING
/* metadata tag structure */
typedef struct
{
char *item;
char *value;
} mp4ff_tag_t;
/* metadata list structure */
typedef struct
{
mp4ff_tag_t *tags;
uint32_t count;
} mp4ff_metadata_t;
int32_t mp4ff_meta_update(mp4ff_callback_t *f,const mp4ff_metadata_t * data);
#endif
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif
#ifndef _MP4FF_INT_TYPES_H_
#define _MP4FF_INT_TYPES_H_
#ifdef _WIN32
typedef char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef long int32_t;
typedef unsigned long uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#endif
/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003-2004 M. Bakker, Ahead Software AG, http://www.nero.com
**
** 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.
**
** Any non-GPL usage of this software or parts of this software is strictly
** forbidden.
**
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
** $Id: mp4sample.c,v 1.15 2004/01/11 15:52:19 menno Exp $
**/
#include <stdlib.h>
#include "mp4ffint.h"
static int32_t mp4ff_chunk_of_sample(const mp4ff_t *f, const int32_t track, const int32_t sample,
int32_t *chunk_sample, int32_t *chunk)
{
int32_t total_entries = 0;
int32_t chunk2entry;
int32_t chunk1, chunk2, chunk1samples, range_samples, total = 0;
if (f->track[track] == NULL)
{
return -1;
}
total_entries = f->track[track]->stsc_entry_count;
chunk1 = 1;
chunk1samples = 0;
chunk2entry = 0;
do
{
chunk2 = f->track[track]->stsc_first_chunk[chunk2entry];
*chunk = chunk2 - chunk1;
range_samples = *chunk * chunk1samples;
if (sample < total + range_samples) break;
chunk1samples = f->track[track]->stsc_samples_per_chunk[chunk2entry];
chunk1 = chunk2;
if(chunk2entry < total_entries)
{
chunk2entry++;
total += range_samples;
}
} while (chunk2entry < total_entries);
if (chunk1samples)
*chunk = (sample - total) / chunk1samples + chunk1;
else
*chunk = 1;
*chunk_sample = total + (*chunk - chunk1) * chunk1samples;
return 0;
}
static int32_t mp4ff_chunk_to_offset(const mp4ff_t *f, const int32_t track, const int32_t chunk)
{
const mp4ff_track_t * p_track = f->track[track];
if (p_track->stco_entry_count && (chunk > p_track->stco_entry_count))
{
return p_track->stco_chunk_offset[p_track->stco_entry_count - 1];
} else if (p_track->stco_entry_count) {
return p_track->stco_chunk_offset[chunk - 1];
} else {
return 8;
}
return 0;
}
static int32_t mp4ff_sample_range_size(const mp4ff_t *f, const int32_t track,
const int32_t chunk_sample, const int32_t sample)
{
int32_t i, total;
const mp4ff_track_t * p_track = f->track[track];
if (p_track->stsz_sample_size)
{
return (sample - chunk_sample) * p_track->stsz_sample_size;
}
else
{
if (sample>=p_track->stsz_sample_count) return 0;//error
for(i = chunk_sample, total = 0; i < sample; i++)
{
total += p_track->stsz_table[i];
}
}
return total;
}
static int32_t mp4ff_sample_to_offset(const mp4ff_t *f, const int32_t track, const int32_t sample)
{
int32_t chunk, chunk_sample, chunk_offset1, chunk_offset2;
mp4ff_chunk_of_sample(f, track, sample, &chunk_sample, &chunk);
chunk_offset1 = mp4ff_chunk_to_offset(f, track, chunk);
chunk_offset2 = chunk_offset1 + mp4ff_sample_range_size(f, track, chunk_sample, sample);
return chunk_offset2;
}
int32_t mp4ff_audio_frame_size(const mp4ff_t *f, const int32_t track, const int32_t sample)
{
int32_t bytes;
const mp4ff_track_t * p_track = f->track[track];
if (p_track->stsz_sample_size)
{
bytes = p_track->stsz_sample_size;
} else {
bytes = p_track->stsz_table[sample];
}
return bytes;
}
int32_t mp4ff_set_sample_position(mp4ff_t *f, const int32_t track, const int32_t sample)
{
int32_t offset;
offset = mp4ff_sample_to_offset(f, track, sample);
mp4ff_set_position(f, offset);
return 0;
}
/*
** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding
** Copyright (C) 2003-2004 M. Bakker, Ahead Software AG, http://www.nero.com
**
** 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.
**
** Any non-GPL usage of this software or parts of this software is strictly
** forbidden.
**
** Commercial non-GPL licensing of this software is possible.
** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
**
** $Id: mp4util.c,v 1.15 2004/01/11 15:52:19 menno Exp $
**/
#include "mp4ffint.h"
#include <stdlib.h>
int32_t mp4ff_read_data(mp4ff_t *f, int8_t *data, uint32_t size)
{
int32_t result = 1;
result = f->stream->read(f->stream->user_data, data, size);
f->current_position += size;
return result;
}
int32_t mp4ff_truncate(mp4ff_t * f)
{
return f->stream->truncate(f->stream->user_data);
}
int32_t mp4ff_write_data(mp4ff_t *f, int8_t *data, uint32_t size)
{
int32_t result = 1;
result = f->stream->write(f->stream->user_data, data, size);
f->current_position += size;
return result;
}
int32_t mp4ff_write_int32(mp4ff_t *f,const uint32_t data)
{
uint32_t result;
uint32_t a, b, c, d;
int8_t temp[4];
*(uint32_t*)temp = data;
a = (uint8_t)temp[0];
b = (uint8_t)temp[1];
c = (uint8_t)temp[2];
d = (uint8_t)temp[3];
result = (a<<24) | (b<<16) | (c<<8) | d;
return mp4ff_write_data(f,(uint8_t*)&result,sizeof(result));
}
int32_t mp4ff_set_position(mp4ff_t *f, const int64_t position)
{
f->stream->seek(f->stream->user_data, position);
f->current_position = position;
return 0;
}
int64_t mp4ff_position(const mp4ff_t *f)
{
return f->current_position;
}
uint64_t mp4ff_read_int64(mp4ff_t *f)
{
uint8_t data[8];
uint64_t result = 0;
int8_t i;
mp4ff_read_data(f, data, 8);
for (i = 0; i < 8; i++)
{
result |= ((uint64_t)data[i]) << ((7 - i) * 8);
}
return result;
}
uint32_t mp4ff_read_int32(mp4ff_t *f)
{
uint32_t result;
uint32_t a, b, c, d;
int8_t data[4];
mp4ff_read_data(f, data, 4);
a = (uint8_t)data[0];
b = (uint8_t)data[1];
c = (uint8_t)data[2];
d = (uint8_t)data[3];
result = (a<<24) | (b<<16) | (c<<8) | d;
return (uint32_t)result;
}
uint32_t mp4ff_read_int24(mp4ff_t *f)
{
uint32_t result;
uint32_t a, b, c;
int8_t data[4];
mp4ff_read_data(f, data, 3);
a = (uint8_t)data[0];
b = (uint8_t)data[1];
c = (uint8_t)data[2];
result = (a<<16) | (b<<8) | c;
return (uint32_t)result;
}
uint16_t mp4ff_read_int16(mp4ff_t *f)
{
uint32_t result;
uint32_t a, b;
int8_t data[2];
mp4ff_read_data(f, data, 2);
a = (uint8_t)data[0];
b = (uint8_t)data[1];
result = (a<<8) | b;
return (uint16_t)result;
}
char * mp4ff_read_string(mp4ff_t * f,uint32_t length)
{
char * str = (char*)malloc(length + 1);
if (str!=0)
{
if ((uint32_t)mp4ff_read_data(f,str,length)!=length)
{
free(str);
str = 0;
}
else
{
str[length] = 0;
}
}
return str;
}
uint8_t mp4ff_read_char(mp4ff_t *f)
{
uint8_t output;
mp4ff_read_data(f, &output, 1);
return output;
}
uint32_t mp4ff_read_mp4_descr_length(mp4ff_t *f)
{
uint8_t b;
uint8_t numBytes = 0;
uint32_t length = 0;
do
{
b = mp4ff_read_char(f);
numBytes++;
length = (length << 7) | (b & 0x7F);
} while ((b & 0x80) && numBytes < 4);
return length;
}
......@@ -19,6 +19,8 @@
#ifndef MPD_TYPES_H
#define MPD_TYPES_H
#include "../config.h"
typedef unsigned char mpd_uint8;
typedef signed char mpd_sint8;
......
......@@ -19,6 +19,8 @@
#ifndef MYFPRINTF_H
#define MYFPRINTF_H
#include "../config.h"
#include <stdio.h>
void myfprintfStdLogMode(FILE * out, FILE * err);
......
......@@ -16,9 +16,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_OGG
#include "ogg_decode.h"
#ifdef HAVE_OGG
#include "command.h"
#include "utils.h"
#include "audio.h"
......@@ -31,6 +32,31 @@
#include <string.h>
#include <vorbis/vorbisfile.h>
#ifdef WORDS_BIGENDIAN
#define OGG_DECODE_USE_BIGENDIAN 1
#else
#define OGG_DECODE_USE_BIGENDIAN 0
#endif
int getOggTotalTime(char * file) {
OggVorbis_File vf;
FILE * oggfp;
int totalTime;
if(!(oggfp = fopen(file,"r"))) return -1;
if(ov_open(oggfp, &vf, NULL, 0) < 0) {
fclose(oggfp);
return -1;
}
totalTime = ov_time_total(&vf,-1)+0.5;
ov_clear(&vf);
return totalTime;
}
int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
{
OggVorbis_File vf;
......@@ -69,7 +95,7 @@ int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
while(!eof) {
if(dc->seek) {
cb->end = 0;
cb->end = cb->begin;
cb->wrap = 0;
chunkpos = 0;
ov_time_seek_page(&vf,dc->seekWhere);
......@@ -77,7 +103,8 @@ int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
}
ret = ov_read(&vf,chunk+chunkpos,
CHUNK_SIZE-chunkpos,
0,2,1,
OGG_DECODE_USE_BIGENDIAN,
2,1,
&current_section);
if(ret<=0) eof = 1;
else chunkpos+=ret;
......@@ -89,17 +116,13 @@ int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
}
if(dc->stop) break;
else if(dc->seek) continue;
#ifdef WORDS_BIGENDIAN
pcm_changeBufferEndianness(chunk,CHUNK_SIZE,
af->bits);
#endif
memcpy(cb->chunks+cb->end*CHUNK_SIZE,
chunk,chunkpos);
cb->chunkSize[cb->end] = chunkpos;
chunkpos = 0;
cb->times[cb->end] = ov_time_tell(&vf);
if((test = ov_bitrate_instant(&vf))>0) {
bitRate = test/1000;
bitRate = test/1024;
}
cb->bitRate[cb->end] = bitRate;
cb->end++;
......
......@@ -19,10 +19,14 @@
#ifndef OGG_DECODE_H
#define OGG_DECODE_H
#include "../config.h"
#include "playerData.h"
#include <stdio.h>
int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
int getOggTotalTime(char * file);
#endif
......@@ -87,40 +87,52 @@ char * getFsCharset() {
}
void initPaths() {
#ifdef HAVE_LOCALE
#ifdef HAVE_LANGINFO
char * originalLocale;
#endif
#endif
char * charset = NULL;
char * originalLocale;
if(getConf()[CONF_FS_CHARSET]) {
charset = strdup(getConf()[CONF_FS_CHARSET]);
}
#ifdef HAVE_LOCALE
#ifdef HAVE_LANGINFO
else if((originalLocale = setlocale(LC_ALL,""))) {
else if((originalLocale = setlocale(LC_CTYPE,NULL))) {
char * temp;
char * currentLocale;
originalLocale = strdup(originalLocale);
if((temp = nl_langinfo(CODESET))) {
charset = strdup(temp);
if(!(currentLocale = setlocale(LC_CTYPE,""))) {
ERROR("problems setting current locale with "
"setlocale()\n");
}
else ERROR("problems getting charset for locale\n");
if(!setlocale(LC_ALL,originalLocale)) {
ERROR("problems resetting locale with setlocale()\n");
else {
if(strcmp(currentLocale,"C")==0 ||
strcmp(currentLocale,"POSIX")==0)
{
ERROR("current locale is \"%s\"\n",
currentLocale);
}
else if((temp = nl_langinfo(CODESET))) {
charset = strdup(temp);
}
else ERROR("problems getting charset for locale\n");
if(!setlocale(LC_CTYPE,originalLocale)) {
ERROR("problems resetting locale with setlocale()\n");
}
}
free(originalLocale);
}
else ERROR("problems getting locale with setlocale()\n");
#endif
#endif
else ERROR("problems getting locale with setlocale()\n");
if(charset) {
setFsCharset(charset);
free(charset);
}
else {
ERROR("setting filesystem charset to UTF-8\n");
setFsCharset("UTF-8");
ERROR("setting filesystem charset to ISO-8859-1\n");
setFsCharset("ISO-8859-1");
}
}
......
......@@ -19,6 +19,8 @@
#ifndef PATH_H
#define PATH_H
#include "../config.h"
#include <sys/param.h>
extern char musicDir[MAXPATHLEN+1];
......
......@@ -19,6 +19,8 @@
#ifndef PCM_UTILS_H
#define PMC_UTILS_H
#include "../config.h"
#include "audio.h"
#include <stdlib.h>
......
......@@ -19,6 +19,8 @@
#ifndef PERMISSION_H
#define PERMISSION_H
#include "../config.h"
#define PERMISSION_READ 1
#define PERMISSION_ADD 2
#define PERMISSION_CONTROL 4
......
......@@ -108,9 +108,9 @@ int playerInit() {
sigaction(SIGTERM,&sa,NULL);
close(listenSocket);
finishPlaylist();
freeAllInterfaces();
closeMp3Directory();
finishPlaylist();
closeTables();
finishPaths();
finishPermissions();
......@@ -149,8 +149,31 @@ int playerInit() {
return 0;
}
int playerGetDecodeType(char * utf8file) {
if(0);
#ifdef HAVE_MAD
if(isMp3(utf8file,NULL)) return DECODE_TYPE_MP3;
#endif
#ifdef HAVE_OGG
if(isOgg(utf8file,NULL)) return DECODE_TYPE_OGG;
#endif
#ifdef HAVE_FLAC
if(isFlac(utf8file,NULL)) return DECODE_TYPE_FLAC;
#endif
#ifdef HAVE_AUDIOFILE
if(isWave(utf8file,NULL)) return DECODE_TYPE_AUDIOFILE;
#endif
#ifdef HAVE_FAAD
if(isAac(utf8file,NULL)) return DECODE_TYPE_AAC;
if(isMp4(utf8file,NULL)) return DECODE_TYPE_MP4;
#endif
return -1;
}
int playerPlay(FILE * fp, char * utf8file) {
PlayerControl * pc = &(getPlayerData()->playerControl);
int decodeType;
if(fp==NULL) fp = stderr;
if(playerStop(fp)<0) return -1;
......@@ -163,25 +186,14 @@ int playerPlay(FILE * fp, char * utf8file) {
return 0;
}
}
if(0);
#ifdef HAVE_MAD
else if(isMp3(utf8file)) pc->decodeType = DECODE_TYPE_MP3;
#endif
#ifdef HAVE_OGG
else if(isOgg(utf8file)) pc->decodeType = DECODE_TYPE_OGG;
#endif
#ifdef HAVE_FLAC
else if(isFlac(utf8file)) pc->decodeType = DECODE_TYPE_FLAC;
#endif
#ifdef HAVE_AUDIOFILE
else if(isWave(utf8file)) pc->decodeType = DECODE_TYPE_AUDIOFILE;
#endif
else {
decodeType = playerGetDecodeType(utf8file);
if(decodeType < 0) {
strncpy(pc->erroredFile,pc->file,MAXPATHLEN);
pc->error = PLAYER_ERROR_UNKTYPE;
return 0;
}
pc->decodeType = decodeType;
strncpy(pc->file,rmp2amp(utf8ToFsCharset(utf8file)),MAXPATHLEN);
......@@ -191,7 +203,7 @@ int playerPlay(FILE * fp, char * utf8file) {
return -1;
}
while(player_pid>0 && pc->play) usleep(10);
while(player_pid>0 && pc->play) usleep(1000);
return 0;
}
......@@ -201,7 +213,7 @@ int playerStop(FILE * fp) {
if(player_pid>0 && pc->state!=PLAYER_STATE_STOP) {
pc->stop = 1;
while(player_pid>0 && pc->stop) usleep(10);
while(player_pid>0 && pc->stop) usleep(1000);
}
pc->queueState = PLAYER_QUEUE_BLANK;
......@@ -227,7 +239,7 @@ int playerPause(FILE * fp) {
if(player_pid>0 && pc->state!=PLAYER_STATE_STOP) {
pc->pause = 1;
while(player_pid>0 && pc->pause) usleep(10);
while(player_pid>0 && pc->pause) usleep(1000);
}
return 0;
......@@ -311,26 +323,15 @@ void playerCloseAudio() {
int queueSong(char * utf8file) {
PlayerControl * pc = &(getPlayerData()->playerControl);
int decodeType;
if(pc->queueState==PLAYER_QUEUE_BLANK) {
strncpy(pc->file,rmp2amp(utf8ToFsCharset(utf8file)),MAXPATHLEN);
if(0);
#ifdef HAVE_MAD
else if(isMp3(utf8file)) pc->decodeType = DECODE_TYPE_MP3;
#endif
#ifdef HAVE_OGG
else if(isOgg(utf8file)) pc->decodeType = DECODE_TYPE_OGG;
#endif
#ifdef HAVE_FLAC
else if(isFlac(utf8file)) pc->decodeType = DECODE_TYPE_FLAC;
#endif
#ifdef HAVE_AUDIOFILE
else if(isWave(utf8file)) {
pc->decodeType = DECODE_TYPE_AUDIOFILE;
}
#endif
else return -1;
decodeType = playerGetDecodeType(utf8file);
if(decodeType < 0) return -1;
pc->decodeType = decodeType;
pc->queueState = PLAYER_QUEUE_FULL;
return 0;
}
......@@ -356,7 +357,7 @@ void playerQueueLock() {
if(player_pid>0 && pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
{
pc->lockQueue = 1;
while(player_pid>0 && pc->lockQueue) usleep(10);
while(player_pid>0 && pc->lockQueue) usleep(1000);
}
}
......@@ -366,13 +367,14 @@ void playerQueueUnlock() {
if(player_pid>0 && pc->queueLockState==PLAYER_QUEUE_LOCKED)
{
pc->unlockQueue = 1;
while(player_pid>0 && pc->unlockQueue) usleep(10);
while(player_pid>0 && pc->unlockQueue) usleep(1000);
}
}
int playerSeek(FILE * fp, char * utf8file, float time) {
PlayerControl * pc = &(getPlayerData()->playerControl);
char * file;
int decodeType;
if(pc->state==PLAYER_STATE_STOP) {
myfprintf(fp,"%s player not currently playing\n",
......@@ -381,15 +383,22 @@ int playerSeek(FILE * fp, char * utf8file, float time) {
}
file = rmp2amp(utf8ToFsCharset(utf8file));
if(strcmp(pc->file,file)!=0) strncpy(pc->file,file,MAXPATHLEN);
/*if(playerStop(fp)<0) return -1;
if(playerPlay(stderr,file)<0) return -1;*/
/*}*/
if(strcmp(pc->file,file)!=0) {
decodeType = playerGetDecodeType(utf8file);
if(decodeType < 0) {
printf("%s unknown file type: %s\n",
COMMAND_RESPOND_ERROR, utf8file);
return -1;
}
pc->decodeType = decodeType;
strncpy(pc->file,file,MAXPATHLEN);
}
if(pc->error==PLAYER_ERROR_NOERROR) {
pc->seekWhere = time;
pc->seek = 1;
while(player_pid>0 && pc->seek) usleep(10);
while(player_pid>0 && pc->seek) usleep(1000);
}
return 0;
......
......@@ -19,6 +19,8 @@
#ifndef PLAYER_H
#define PLAYER_H
#include "../config.h"
#include "mpd_types.h"
#include <stdio.h>
......
......@@ -19,6 +19,8 @@
#ifndef PLAYER_DATA_H
#define PLAYER_DATA_H
#include "../config.h"
#include "audio.h"
#include "player.h"
#include "decode.h"
......
......@@ -244,6 +244,8 @@ void loadPlaylistFromStateFile(FILE * fp, char * buffer, int state, int current,
}
if(state==PLAYER_STATE_PAUSE) {
playerPause(stderr);
}
if(state!=PLAYER_STATE_STOP) {
seekSongInPlaylist(stderr,playlist.length-1,
time);
}
......@@ -633,17 +635,6 @@ void deleteASongFromPlaylist(Song * song) {
}
}
void deleteSongsFromPlaylist(SongList * songList) {
ListNode * node = songList->firstNode;
Song * song;
while(node) {
song = (Song *)node->data;
deleteASongFromPlaylist(song);
node = node->nextNode;
}
}
int stopPlaylist(FILE * fp) {
DEBUG("playlist: stop\n");
if(playerStop(fp)<0) return -1;
......
......@@ -19,6 +19,8 @@
#ifndef PLAYLIST_H
#define PLAYLIST_H
#include "../config.h"
#include "song.h"
#include <stdio.h>
......@@ -67,8 +69,6 @@ int deletePlaylist(FILE * fp, char * utf8file);
void deleteASongFromPlaylist(Song * song);
void deleteSongsFromPlaylist(SongList * songList);
int moveSongInPlaylist(FILE * fp, int from, int to);
int swapSongsInPlaylist(FILE * fp, int song1, int song2);
......@@ -93,4 +93,6 @@ void playPlaylistIfPlayerStopped();
int seekSongInPlaylist(FILE * fp, int song, float time);
void incrPlaylistVersion();
#endif
......@@ -19,6 +19,8 @@
#ifndef SIG_HANDLERS_H
#define SIG_HANDLERS_H
#include "../config.h"
void initSigHandlers();
void finishSigHandlers();
......
......@@ -23,6 +23,13 @@
#include "utils.h"
#include "tag.h"
#include "log.h"
#include "mp3_decode.h"
#include "audiofile_decode.h"
#include "ogg_decode.h"
#include "flac_decode.h"
#include "path.h"
#include "playlist.h"
#include "tables.h"
#define SONG_KEY "key: "
#define SONG_FILE "file: "
......@@ -36,38 +43,62 @@
#include <stdlib.h>
#include <string.h>
Song * newSong(char * utf8file) {
Song * newNullSong() {
Song * song = malloc(sizeof(Song));
song->tag = NULL;
song->utf8file = NULL;
return song;
}
Song * newSong(char * utf8file) {
Song * song = newNullSong();
song->utf8file = strdup(utf8file);
if(0);
#ifdef HAVE_OGG
if((song->mtime = isOgg(utf8file))) {
else if(isOgg(utf8file,&(song->mtime))) {
song->tag = oggTagDup(utf8file);
return song;
}
#endif
#ifdef HAVE_FLAC
if((song->mtime = isFlac(utf8file))) {
else if((isFlac(utf8file,&(song->mtime)))) {
song->tag = flacTagDup(utf8file);
return song;
}
#endif
#ifdef HAVE_MAD
if((song->mtime = isMp3(utf8file))) {
else if(isMp3(utf8file,&(song->mtime))) {
song->tag = mp3TagDup(utf8file);
return song;
}
#endif
#ifdef HAVE_AUDIOFILE
if((song->mtime = isWave(utf8file))) {
else if(isWave(utf8file,&(song->mtime))) {
song->tag = audiofileTagDup(utf8file);
return song;
}
#endif
#ifdef HAVE_FAAD
else if(isAac(utf8file,&(song->mtime))) {
song->tag = aacTagDup(utf8file);
}
else if(isMp4(utf8file,&(song->mtime))) {
song->tag = mp4TagDup(utf8file);
}
#endif
if(!song->tag || song->tag->time<0) {
freeSong(song);
song = NULL;
}
else addSongToTables(song);
return song;
}
void freeSong(Song * song) {
deleteASongFromPlaylist(song);
removeASongFromTables(song);
free(song->utf8file);
if(song->tag) freeMpdTag(song->tag);
free(song);
......@@ -78,14 +109,13 @@ SongList * newSongList() {
}
Song * addSongToList(SongList * list, char * key, char * utf8file) {
Song * song;
Song * song = NULL;
if(isMusic(utf8file)) {
if(isMusic(utf8file,NULL)) {
song = newSong(utf8file);
}
else {
return NULL;
}
if(song==NULL) return NULL;
insertInList(list,key,(void *)song);
......@@ -144,9 +174,7 @@ void readSongInfoIntoList(FILE * fp, SongList * list) {
free(key);
}
key = strdup(&(buffer[strlen(SONG_KEY)]));
song = malloc(sizeof(Song));
song->tag = NULL;
song->utf8file = NULL;
song = newNullSong();
}
else if(0==strncmp(SONG_FILE,buffer,strlen(SONG_FILE))) {
if(!song || song->utf8file) {
......@@ -179,7 +207,7 @@ void readSongInfoIntoList(FILE * fp, SongList * list) {
song->mtime = atoi(&(buffer[strlen(SONG_TITLE)]));
}
else {
ERROR("unknown line in db: %s\n",buffer);
ERROR("songinfo: unknown line in db: %s\n",buffer);
exit(-1);
}
}
......@@ -192,32 +220,47 @@ void readSongInfoIntoList(FILE * fp, SongList * list) {
}
int updateSongInfo(Song * song) {
char * utf8file = song->utf8file;
removeASongFromTables(song);
if(song->tag) freeMpdTag(song->tag);
#ifdef HAVE_MAD
if((song->mtime = isMp3(song->utf8file))) {
song->tag = mp3TagDup(song->utf8file);
return 0;
}
#endif
song->tag = NULL;
if(0);
#ifdef HAVE_OGG
if((song->mtime = isOgg(song->utf8file))) {
song->tag = oggTagDup(song->utf8file);
return 0;
else if(isOgg(utf8file,&(song->mtime))) {
song->tag = oggTagDup(utf8file);
}
#endif
#ifdef HAVE_FLAC
if((song->mtime = isFlac(song->utf8file))) {
song->tag = flacTagDup(song->utf8file);
return 0;
else if((isFlac(utf8file,&(song->mtime)))) {
song->tag = flacTagDup(utf8file);
}
#endif
#ifdef HAVE_MAD
else if(isMp3(utf8file,&(song->mtime))) {
song->tag = mp3TagDup(utf8file);
}
#endif
#ifdef HAVE_AUDIOFILE
if((song->mtime = isWave(song->utf8file))) {
song->tag = audiofileTagDup(song->utf8file);
return 0;
else if(isWave(utf8file,&(song->mtime))) {
song->tag = audiofileTagDup(utf8file);
}
#endif
return -1;
#ifdef HAVE_FAAD
else if(isAac(utf8file,&(song->mtime))) {
song->tag = aacTagDup(utf8file);
}
else if(isMp4(utf8file,&(song->mtime))) {
song->tag = mp4TagDup(utf8file);
}
#endif
if(!song->tag || song->tag->time<0) return -1;
else addSongToTables(song);
return 0;
}
Song * songDup(Song * song) {
......
......@@ -19,6 +19,8 @@
#ifndef SONG_H
#define SONG_H
#include "../config.h"
#define SONG_BEGIN "songList begin"
#define SONG_END "songList end"
......
......@@ -19,6 +19,8 @@
#ifndef STATS_H
#define STATS_H
#include "../config.h"
#include <stdio.h>
typedef struct _Stats {
......
......@@ -129,17 +129,6 @@ void removeASongFromTables(Song * song) {
removeSongFromArtistTable(song);
}
void removeSongsFromTables(SongList * songList) {
ListNode * node = songList->firstNode;
Song * song;
while(node) {
song = (Song *)node->data;
removeASongFromTables(song);
node = node->nextNode;
}
}
unsigned long numberOfSongs() {
return 0;
}
......
......@@ -19,6 +19,8 @@
#ifndef TABLES_H
#define TABLES_H
#include "../config.h"
#include "song.h"
#include <stdio.h>
......@@ -28,8 +30,6 @@ void closeTables();
void addSongToTables(Song * song);
void removeSongsFromTables(SongList * songList);
void removeASongFromTables(Song * song);
unsigned long numberOfSongs();
......
......@@ -22,6 +22,9 @@
#include "sig_handlers.h"
#include "mp3_decode.h"
#include "audiofile_decode.h"
#include "mp4_decode.h"
#include "aac_decode.h"
#include "utils.h"
#include <sys/stat.h>
#include <stdlib.h>
......@@ -43,6 +46,9 @@
#include <id3tag.h>
#endif
#endif
#ifdef HAVE_FAAD
#include "mp4ff/mp4ff.h"
#endif
void printMpdTag(FILE * fp, MpdTag * tag) {
if(tag->artist) myfprintf(fp,"Artist: %s\n",tag->artist);
......@@ -102,24 +108,28 @@ MpdTag * id3Dup(char * utf8filename) {
str = getID3Info(tag,ID3_FRAME_ARTIST);
if(str) {
if(!ret) ret = newMpdTag();
stripReturnChar(str);
ret->artist = str;
}
str = getID3Info(tag,ID3_FRAME_TITLE);
if(str) {
if(!ret) ret = newMpdTag();
stripReturnChar(str);
ret->title = str;
}
str = getID3Info(tag,ID3_FRAME_ALBUM);
if(str) {
if(!ret) ret = newMpdTag();
stripReturnChar(str);
ret->album = str;
}
str = getID3Info(tag,ID3_FRAME_TRACK);
if(str) {
if(!ret) ret = newMpdTag();
stripReturnChar(str);
ret->track = str;
}
......@@ -162,6 +172,121 @@ MpdTag * mp3TagDup(char * utf8file) {
}
#endif
#ifdef HAVE_FAAD
MpdTag * aacTagDup(char * utf8file) {
MpdTag * ret = NULL;
int time;
blockSignals();
time = getAacTotalTime(rmp2amp(utf8ToFsCharset(utf8file)));
if(time>=0) {
if((ret = id3Dup(utf8file))==NULL) ret = newMpdTag();
ret->time = time;
}
unblockSignals();
return ret;
}
MpdTag * mp4DataDup(char * utf8file, int * mp4MetadataFound) {
MpdTag * ret = NULL;
FILE * fh;
mp4ff_t * mp4fh;
mp4ff_callback_t * cb;
int32_t track;
int32_t time;
int32_t scale;
*mp4MetadataFound = 0;
blockSignals();
fh = fopen(rmp2amp(utf8ToFsCharset(utf8file)),"r");
if(!fh) {
unblockSignals();
return NULL;
}
cb = malloc(sizeof(mp4ff_callback_t));
cb->read = mp4_readCallback;
cb->seek = mp4_seekCallback;
cb->user_data = fh;
mp4fh = mp4ff_open_read(cb);
if(!mp4fh) {
free(cb);
fclose(fh);
unblockSignals();
return NULL;
}
track = mp4_getAACTrack(mp4fh);
if(track < 0) {
mp4ff_close(mp4fh);
fclose(fh);
free(cb);
unblockSignals();
return NULL;
}
ret = newMpdTag();
time = mp4ff_get_track_duration_use_offsets(mp4fh,track);
scale = mp4ff_time_scale(mp4fh,track);
if(scale < 0) {
mp4ff_close(mp4fh);
fclose(fh);
free(cb);
freeMpdTag(ret);
unblockSignals();
return NULL;
}
ret->time = ((float)time)/scale+0.5;
if(!mp4ff_meta_get_artist(mp4fh,&ret->artist)) {
*mp4MetadataFound = 1;
}
if(!mp4ff_meta_get_album(mp4fh,&ret->album)) {
*mp4MetadataFound = 1;
}
if(!mp4ff_meta_get_title(mp4fh,&ret->title)) {
*mp4MetadataFound = 1;
}
if(!mp4ff_meta_get_track(mp4fh,&ret->track)) {
*mp4MetadataFound = 1;
}
mp4ff_close(mp4fh);
fclose(fh);
free(cb);
unblockSignals();
return ret;
}
MpdTag * mp4TagDup(char * utf8file) {
MpdTag * ret = NULL;
int mp4MetadataFound = 0;
ret = mp4DataDup(utf8file,&mp4MetadataFound);
if(!mp4MetadataFound) {
MpdTag * temp = id3Dup(utf8file);
if(temp) {
temp->time = ret->time;
freeMpdTag(ret);
ret = temp;
}
}
return ret;
}
#endif
#ifdef HAVE_OGG
MpdTag * oggTagDup(char * utf8file) {
MpdTag * ret = NULL;
......@@ -195,21 +320,25 @@ MpdTag * oggTagDup(char * utf8file) {
if(!s1 || !s2);
else if(0==strcasecmp(s1,"artist")) {
if(!ret->artist) {
stripReturnChar(s2);
ret->artist = strdup(s2);
}
}
else if(0==strcasecmp(s1,"title")) {
if(!ret->title) {
stripReturnChar(s2);
ret->title = strdup(s2);
}
}
else if(0==strcasecmp(s1,"album")) {
if(!ret->album) {
stripReturnChar(s2);
ret->album = strdup(s2);
}
}
else if(0==strcasecmp(s1,"tracknumber")) {
if(!ret->track) {
stripReturnChar(s2);
ret->track = strdup(s2);
}
}
......@@ -257,6 +386,7 @@ MpdTag * flacMetadataDup(char * utf8file, int * vorbisCommentFound) {
dup = malloc(len+1);
memcpy(dup,&(block->data.vorbis_comment.comments[offset].entry[pos]),len);
dup[len] = '\0';
stripReturnChar(dup);
ret->artist = dup;
}
}
......@@ -270,6 +400,7 @@ MpdTag * flacMetadataDup(char * utf8file, int * vorbisCommentFound) {
dup = malloc(len+1);
memcpy(dup,&(block->data.vorbis_comment.comments[offset].entry[pos]),len);
dup[len] = '\0';
stripReturnChar(dup);
ret->album = dup;
}
}
......@@ -283,6 +414,7 @@ MpdTag * flacMetadataDup(char * utf8file, int * vorbisCommentFound) {
dup = malloc(len+1);
memcpy(dup,&(block->data.vorbis_comment.comments[offset].entry[pos]),len);
dup[len] = '\0';
stripReturnChar(dup);
ret->title = dup;
}
}
......@@ -296,6 +428,7 @@ MpdTag * flacMetadataDup(char * utf8file, int * vorbisCommentFound) {
dup = malloc(len+1);
memcpy(dup,&(block->data.vorbis_comment.comments[offset].entry[pos]),len);
dup[len] = '\0';
stripReturnChar(dup);
ret->track = dup;
}
}
......
......@@ -19,6 +19,8 @@
#ifndef TAG_H
#define TAG_H
#include "../config.h"
#include <stdio.h>
typedef struct _MpdTag {
......@@ -37,6 +39,12 @@ void freeMpdTag(MpdTag * tag);
MpdTag * mp3TagDup(char * utf8file);
#endif
#ifdef HAVE_FAAD
MpdTag * aacTagDup(char * utf8file);
MpdTag * mp4TagDup(char * utf8file);
#endif
#ifdef HAVE_OGG
MpdTag * oggTagDup(char * utf8file);
#endif
......
......@@ -37,3 +37,9 @@ char * strDupToUpper(char * str) {
return ret;
}
void stripReturnChar(char * string) {
while(string && (string = strstr(string,"\n"))) {
*string = ' ';
}
}
......@@ -19,10 +19,14 @@
#ifndef UTILS_H
#define UTILS_H
#include "../config.h"
#include <stdio.h>
char * myFgets(char * buffer, int bufferSize, FILE * fp);
char * strDupToUpper(char * str);
void stripReturnChar(char * string);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment