Commit ad682eb6 authored by Led's avatar Led

0.11.1-rc1

parent d61a5965
ver 0.11.1 (2004/6/24)
1) Fix a bug that caused "popping" at the beginning of mp3's
2) Fix playlistid command
3) Fix move commands so they don't mess up the song id's
4) Added support for HTTP Proxy
5) Detect and skip recursive links in the music directory
6) Fix addPathToDB() so updating on a specific path doesn't exist correctly adds the parent directories to the DB
ver 0.11.0 (2004/6/18)
1) Support for playing mp3 and Ogg Vorbis streams
2) Non-blocking Update
......
*) add add command that returns song id
*) Optimize read() on cleints
*) add option for inserting at a specific position in the playlist
*) directory.c needs some serious cleanup
*) put some sort of error reporting for streaming/inputStream!
0.12
----
*) add command that only takes file's or url's (no directory's) and returns the songid of the added song
*) allow add commands to specify position to be inserted
*) saved playlist commands for getting the contents of a playlist and appending to a playlist
Post-1.0
--------
......
......@@ -3,7 +3,7 @@
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
timestamp='2003-06-17'
timestamp='2004-01-24'
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
......@@ -136,13 +136,6 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
## for Red Hat Linux
if test -f /etc/redhat-release ; then
VENDOR=redhat ;
else
VENDOR= ;
fi
# Note: order is significant - the case branches are not exclusive.
case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
......@@ -228,6 +221,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
mvmeppc:OpenBSD:*:*)
echo powerpc-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
pegasos:OpenBSD:*:*)
echo powerpc-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
pmax:OpenBSD:*:*)
echo mipsel-unknown-openbsd${UNAME_RELEASE}
exit 0 ;;
......@@ -314,6 +310,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:OS/390:*:*)
echo i370-ibm-openedition
exit 0 ;;
*:OS400:*:*)
echo powerpc-ibm-os400
exit 0 ;;
arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
echo arm-acorn-riscix${UNAME_RELEASE}
exit 0;;
......@@ -406,6 +405,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
*:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
echo m68k-unknown-mint${UNAME_RELEASE}
exit 0 ;;
m68k:machten:*:*)
echo m68k-apple-machten${UNAME_RELEASE}
exit 0 ;;
powerpc:machten:*:*)
echo powerpc-apple-machten${UNAME_RELEASE}
exit 0 ;;
......@@ -741,7 +743,7 @@ EOF
echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit 0 ;;
*:UNICOS/mp:*:*)
echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
echo nv1-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
exit 0 ;;
F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
......@@ -749,6 +751,11 @@ EOF
FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit 0 ;;
5000:UNIX_System_V:4.*:*)
FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
exit 0 ;;
i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
exit 0 ;;
......@@ -758,7 +765,7 @@ EOF
*:BSD/OS:*:*)
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
exit 0 ;;
*:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
*:FreeBSD:*:*)
# Determine whether the default compiler uses glibc.
eval $set_cc_for_build
sed 's/^ //' << EOF >$dummy.c
......@@ -770,7 +777,10 @@ EOF
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
# GNU/KFreeBSD systems have a "k" prefix to indicate we are using
# FreeBSD's kernel, but not the complete OS.
case ${LIBC} in gnu) kernel_only='k' ;; esac
echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
exit 0 ;;
i*:CYGWIN*:*)
echo ${UNAME_MACHINE}-pc-cygwin
......@@ -803,8 +813,13 @@ EOF
echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
exit 0 ;;
*:GNU:*:*)
# the GNU system
echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
exit 0 ;;
*:GNU/*:*:*)
# other systems with GNU libc and userland
echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
exit 0 ;;
i*86:Minix:*:*)
echo ${UNAME_MACHINE}-pc-minix
exit 0 ;;
......@@ -815,7 +830,7 @@ EOF
echo cris-axis-linux-gnu
exit 0 ;;
ia64:Linux:*:*)
echo ${UNAME_MACHINE}-${VENDOR:-unknown}-linux-gnu
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit 0 ;;
m68*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
......@@ -859,10 +874,10 @@ EOF
test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
;;
ppc:Linux:*:*)
echo powerpc-${VENDOR:-unknown}-linux-gnu
echo powerpc-unknown-linux-gnu
exit 0 ;;
ppc64:Linux:*:*)
echo powerpc64-${VENDOR:-unknown}-linux-gnu
echo powerpc64-unknown-linux-gnu
exit 0 ;;
alpha:Linux:*:*)
case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
......@@ -890,7 +905,7 @@ EOF
echo hppa64-unknown-linux-gnu
exit 0 ;;
s390:Linux:*:* | s390x:Linux:*:*)
echo ${UNAME_MACHINE}-${VENDOR:-ibm}-linux-gnu
echo ${UNAME_MACHINE}-ibm-linux
exit 0 ;;
sh64*:Linux:*:*)
echo ${UNAME_MACHINE}-unknown-linux-gnu
......@@ -902,7 +917,7 @@ EOF
echo ${UNAME_MACHINE}-unknown-linux-gnu
exit 0 ;;
x86_64:Linux:*:*)
echo x86_64-${VENDOR:-unknown}-linux-gnu
echo x86_64-unknown-linux-gnu
exit 0 ;;
i*86:Linux:*:*)
# The BFD linker knows what the default object file format is, so
......@@ -952,9 +967,12 @@ EOF
LIBC=gnuaout
#endif
#endif
#ifdef __dietlibc__
LIBC=dietlibc
#endif
EOF
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
test x"${LIBC}" != x && echo "${UNAME_MACHINE}-${VENDOR:-pc}-linux-${LIBC}" && exit 0
test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
;;
i*86:DYNIX/ptx:4*:*)
......@@ -982,6 +1000,9 @@ EOF
i*86:atheos:*:*)
echo ${UNAME_MACHINE}-unknown-atheos
exit 0 ;;
i*86:syllable:*:*)
echo ${UNAME_MACHINE}-pc-syllable
exit 0 ;;
i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
echo i386-unknown-lynxos${UNAME_RELEASE}
exit 0 ;;
......@@ -1053,7 +1074,7 @@ EOF
exit 0 ;;
M68*:*:R3V[567]*:*)
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
OS_REL=''
test -r /etc/.relid \
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
......@@ -1168,7 +1189,7 @@ EOF
*:QNX:*:4*)
echo i386-pc-qnx
exit 0 ;;
NSR-[DGKLNPTVW]:NONSTOP_KERNEL:*:*)
NSR-?:NONSTOP_KERNEL:*:*)
echo nsr-tandem-nsk${UNAME_RELEASE}
exit 0 ;;
*:NonStop-UX:*:*)
......@@ -1212,6 +1233,9 @@ EOF
SEI:*:*:SEIUX)
echo mips-sei-seiux${UNAME_RELEASE}
exit 0 ;;
*:DragonFly:*:*)
echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
exit 0 ;;
esac
#echo '(No uname command or uname output not recognized.)' 1>&2
......
......@@ -3,7 +3,7 @@
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
timestamp='2003-06-18'
timestamp='2004-01-05'
# 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,8 @@ 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* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
......@@ -228,13 +229,14 @@ case $basic_machine in
| a29k \
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
| am33_2.0 \
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
| c4x | clipper \
| d10v | d30v | dlx | dsp16xx \
| fr30 | frv \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \
| ip2k \
| ip2k | iq2000 \
| m32r | m68000 | m68k | m88k | mcore \
| mips | mipsbe | mipseb | mipsel | mipsle \
| mips16 \
......@@ -247,6 +249,7 @@ case $basic_machine in
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa64 | mipsisa64el \
| mipsisa64r2 | mipsisa64r2el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
......@@ -257,7 +260,6 @@ case $basic_machine in
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
| s390 | s390x \
| sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
......@@ -305,7 +307,7 @@ case $basic_machine in
| h8300-* | h8500-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* \
| ip2k-* | iq2000-* \
| m32r-* \
| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
| m88110-* | m88k-* | mcore-* \
......@@ -320,6 +322,7 @@ case $basic_machine in
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64r2-* | mipsisa64r2el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39-* | mipstx39el-* \
......@@ -330,7 +333,6 @@ case $basic_machine in
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| romp-* | rs6000-* \
| s390-* | s390x-* \
| sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
......@@ -378,6 +380,12 @@ case $basic_machine in
amd64)
basic_machine=x86_64-pc
;;
amd64-*)
basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
amd64-*)
basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
amdahl)
basic_machine=580-amdahl
os=-sysv
......@@ -742,6 +750,10 @@ case $basic_machine in
basic_machine=or32-unknown
os=-coff
;;
os400)
basic_machine=powerpc-ibm
os=-os400
;;
OSE68000 | ose68000)
basic_machine=m68000-ericsson
os=-ose
......@@ -833,6 +845,12 @@ 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
......@@ -956,6 +974,10 @@ case $basic_machine in
tower | tower-32)
basic_machine=m68k-ncr
;;
tpf)
basic_machine=s390x-ibm
os=-tpf
;;
udi29k)
basic_machine=a29k-amd
os=-udi
......@@ -1124,19 +1146,19 @@ case $os in
| -aos* \
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
| -hiux* | -386bsd* | -knetbsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
| -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
| -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* | -dnix* | -nx6 | -nx7 | -sei*)
| -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
......@@ -1160,6 +1182,9 @@ case $os in
-mac*)
os=`echo $os | sed -e 's|mac|macos|'`
;;
-linux-dietlibc)
os=-linux-dietlibc
;;
-linux*)
os=`echo $os | sed -e 's|linux|linux-gnu|'`
;;
......@@ -1172,6 +1197,9 @@ case $os in
-opened*)
os=-openedition
;;
-os400*)
os=-os400
;;
-wince*)
os=-wince
;;
......@@ -1193,6 +1221,9 @@ case $os in
-atheos*)
os=-atheos
;;
-syllable*)
os=-syllable
;;
-386bsd)
os=-bsd
;;
......@@ -1215,6 +1246,9 @@ case $os in
-sinix*)
os=-sysv4
;;
-tpf*)
os=-tpf
;;
-triton*)
os=-sysv3
;;
......@@ -1282,9 +1316,9 @@ case $basic_machine in
arm*-semi)
os=-aout
;;
c4x-* | tic4x-*)
os=-coff
;;
c4x-* | tic4x-*)
os=-coff
;;
# This must come before the *-dec entry.
pdp10-*)
os=-tops20
......@@ -1463,9 +1497,15 @@ case $basic_machine in
-mvs* | -opened*)
vendor=ibm
;;
-os400*)
vendor=ibm
;;
-ptx*)
vendor=sequent
;;
-tpf*)
vendor=ibm
;;
-vxsim* | -vxworks* | -windiss*)
vendor=wrs
;;
......
......@@ -2,7 +2,7 @@ dnl AC_INIT(src/main.c)
dnl AM_INIT_AUTOMAKE(mpd, 0.10.0)
AC_PREREQ(2.52)
AC_INIT(mpd, 0.11.0, shank@mercury.chem.pitt.edu)
AC_INIT(mpd, 0.11.1, shank@mercury.chem.pitt.edu)
AM_INIT_AUTOMAKE($PACKAGE_NAME, $PACKAGE_VERSION)
dnl MAD wants this stuff
......
......@@ -159,6 +159,18 @@ of libao on sound cards with very small buffers.
.B save_absolute_paths_in_playlists <yes or no>
This specifies whether relative or absolute paths for song filenames are
used when saving playlists. The default value is "no".
.TP
.B http_proxy_host <string>
Use to specify the proxy host used for http connections.
.TP
.B http_proxy_port <port>
The port that the http proxy host uses.
.TP
.B http_proxy_user <string>
If the http proxy server requires authentication, this specifies the user.
.TP
.B http_proxy_password <string>
If the http proxy server requires authentication, this specifies the password.
.SH EXAMPLES
.TP
Below is an example config file. (Note: '#' at the beginning of a line denotes a comment. The '#' must be the first character/symbol on that line.)
......@@ -240,5 +252,13 @@ bind_to_address "any"
#filesystem_charset "UTF-8"
.br
#replaygain "album"
.br
#http_proxy_host "proxy.isp.com"
.br
#http_proxy_port "8080"
.br
#http_proxy_user "user"
.br
#http_proxy_password "password"
.SH SEE ALSO
mpc(1)
......@@ -79,6 +79,14 @@ error_file "~/.mpd/mpd.error"
##################################
############ HTTP PROXY ################
# http_proxy_host "proxy.isp.com"
# http_proxy_port "8080"
# http_proxy_user "user"
# http_proxy_password "password"
########################################
########### SECURITY SETTINGS ############
# if you start mpd as root, its recommended
# you specify a a user for mpd to run.
......
......@@ -278,6 +278,11 @@ int playAudio(char * playChunk, int size) {
return 0;
}
int isAudioDeviceOpen() {
if(audio_device) return 1;
return 0;
}
void closeAudioDevice() {
#ifdef HAVE_AUDIO
if(audio_device) {
......
......@@ -49,6 +49,8 @@ int playAudio(char * playChunk,int size);
void closeAudioDevice();
int isAudioDeviceOpen();
void audioError();
int isCurrentAudioFormat(AudioFormat * audioFormat);
......
......@@ -771,7 +771,7 @@ void initCommands() {
addCommand(COMMAND_DELETE ,PERMISSION_CONTROL, 1, 1,handleDelete,NULL);
addCommand(COMMAND_DELETEID ,PERMISSION_CONTROL, 1, 1,handleDeleteId,NULL);
addCommand(COMMAND_PLAYLIST ,PERMISSION_READ, 0, 0,handlePlaylist,NULL);
addCommand(COMMAND_PLAYLISTID ,PERMISSION_READ, 0, 0,handlePlaylistId,NULL);
addCommand(COMMAND_PLAYLISTID ,PERMISSION_READ, 0, 1,handlePlaylistId,NULL);
addCommand(COMMAND_SHUFFLE ,PERMISSION_CONTROL, 0, 0,handleShuffle,NULL);
addCommand(COMMAND_CLEAR ,PERMISSION_CONTROL, 0, 0,handleClear,NULL);
addCommand(COMMAND_SAVE ,PERMISSION_CONTROL, 1, 1,handleSave,NULL);
......
......@@ -37,7 +37,7 @@
#define CONF_COMMENT '#'
#define CONF_NUMBER_OF_PARAMS 29
#define CONF_NUMBER_OF_PARAMS 33
#define CONF_NUMBER_OF_PATHS 6
#define CONF_NUMBER_OF_REQUIRED 5
#define CONF_NUMBER_OF_ALLOW_CATS 1
......@@ -125,7 +125,11 @@ char ** readConf(char * file) {
"default_permissions",
"audio_buffer_size",
"replaygain",
"audio_output_format"
"audio_output_format",
"http_proxy_host",
"http_proxy_port",
"http_proxy_user",
"http_proxy_password"
};
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
......@@ -270,4 +274,3 @@ char ** readConf(char * file) {
char ** getConf() {
return conf_params;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -50,6 +50,10 @@
#define CONF_BUFFER_SIZE 26
#define CONF_REPLAYGAIN 27
#define CONF_AUDIO_OUTPUT_FORMAT 28
#define CONF_HTTP_PROXY_HOST 29
#define CONF_HTTP_PROXY_PORT 30
#define CONF_HTTP_PROXY_USER 31
#define CONF_HTTP_PROXY_PASSWORD 32
#define CONF_CAT_CHAR "\n"
......@@ -63,4 +67,3 @@ void initConf();
void writeConf(char * file);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -98,6 +98,12 @@ int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
return (int)chunks;
}
#define playSilenceOrSleep() \
if(isAudioDeviceOpen()) { \
playAudio(silence, CHUNK_SIZE); \
} \
else my_usleep(10000);
#define handleDecodeStart() \
if(decodeWaitedOn) { \
if(dc->state!=DECODE_STATE_START && *decode_pid > 0 && \
......@@ -128,7 +134,7 @@ int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
return; \
} \
else { \
my_usleep(10000); \
my_usleep(10000); \
continue; \
} \
}
......@@ -463,7 +469,7 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
{
processDecodeInput();
if(quit) return;
my_usleep(10000);
playSilenceOrSleep();
}
while(!quit) {
......@@ -480,7 +486,9 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
pc->queueState = PLAYER_QUEUE_DECODE;
kill(getppid(),SIGUSR1);
}
if(next>=0 && doCrossFade==0 && !dc->start) {
if(next>=0 && doCrossFade==0 && !dc->start &&
dc->state!=DECODE_STATE_START)
{
nextChunk = -1;
if(isCurrentAudioFormat(&(cb->audioFormat))) {
doCrossFade = 1;
......@@ -561,10 +569,10 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
quit = 1;
}
pc->totalPlayTime+= sizeToTime*cb->chunkSize[cb->begin];
cb->begin++;
if(cb->begin>=buffered_chunks) {
if( cb->begin+1 >= buffered_chunks ) {
cb->begin = 0;
}
else cb->begin++;
}
else if(next==cb->begin) {
if(doCrossFade==1 && nextChunk>=0) {
......
......@@ -135,6 +135,7 @@ typedef struct _mp3DecodeData {
int flush;
unsigned long bitRate;
InputStream * inStream;
struct audio_dither dither;
} mp3DecodeData;
void initMp3DecodeData(mp3DecodeData * data, InputStream * inStream) {
......@@ -148,8 +149,10 @@ void initMp3DecodeData(mp3DecodeData * data, InputStream * inStream) {
data->currentFrame = 0;
data->flush = 1;
data->inStream = inStream;
memset(&(data->dither), 0, sizeof(struct audio_dither));
mad_stream_init(&data->stream);
data->stream.options |= MAD_OPTION_IGNORECRC;
mad_frame_init(&data->frame);
mad_synth_init(&data->synth);
mad_timer_reset(&data->timer);
......@@ -188,7 +191,10 @@ int fillMp3InputBuffer(mp3DecodeData * data) {
readSize);
if(readed <= 0 && inputStreamAtEOF(data->inStream)) return -1;
/* sleep for a fraction of a second! */
else if(readed <= 0) my_usleep(10000);
else if(readed <= 0) {
readed = 0;
my_usleep(10000);
}
mad_stream_buffer(&data->stream,data->readBuffer,readed+remaining);
(data->stream).error = 0;
......@@ -230,7 +236,10 @@ static MpdTag * mp3_parseId3Tag(mp3DecodeData * data, signed long tagsize) {
else count += len;
}
if(count != tagsize) goto fail;
if(count != tagsize) {
DEBUG("mp3_decode: error parsing ID3 tag\n");
goto fail;
}
id3_data = allocated;
}
......@@ -262,7 +271,9 @@ int decodeNextFrameHeader(mp3DecodeData * data, MpdTag ** tag) {
(data->stream).this_frame);
if(tagsize>0) {
if(tag) *tag =mp3_parseId3Tag(data, tagsize);
if(tag && !(*tag)) {
*tag =mp3_parseId3Tag(data, tagsize);
}
else {
mad_stream_skip(&(data->stream),
tagsize);
......@@ -463,7 +474,6 @@ int getMp3TotalTime(char * file) {
if(openInputStream(&inStream, file) < 0) return -1;
initMp3DecodeData(&data,&inStream);
data.stream.options |= MAD_OPTION_IGNORECRC;
if(decodeFirstFrame(&data, NULL, NULL)<0) ret = -1;
else ret = data.totalTime+0.5;
mp3DecodeDataFinalize(&data);
......@@ -476,7 +486,6 @@ int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data,
DecoderControl * dc, MpdTag ** tag)
{
initMp3DecodeData(data, inStream);
data->stream.options |= MAD_OPTION_IGNORECRC;
*tag = NULL;
if(decodeFirstFrame(data, dc, tag)<0) {
mp3DecodeDataFinalize(data);
......@@ -490,7 +499,6 @@ int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data,
int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
int i;
int ret;
struct audio_dither dither;
int skip;
if(data->currentFrame>=data->highestFrame) {
......@@ -549,28 +557,30 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
sample = (mpd_sint16 *)data->outputPtr;
*sample = (mpd_sint16) audio_linear_dither(16,
(data->synth).pcm.samples[0][i],
&dither);
&(data->dither));
data->outputPtr+=2;
if(MAD_NCHANNELS(&(data->frame).header)==2) {
sample = (mpd_sint16 *)data->outputPtr;
*sample = (mpd_sint16) audio_linear_dither(16,
(data->synth).pcm.samples[1][i],
&dither);
&(data->dither));
data->outputPtr+=2;
}
if(data->outputPtr==data->outputBufferEnd) {
if(data->outputPtr>=data->outputBufferEnd) {
long ret;
ret = sendDataToOutputBuffer(cb,
data->inStream,
dc,
data->inStream->seekable,
data->outputBuffer,
MP3_DATA_OUTPUT_BUFFER_SIZE,
data->outputPtr-
data->outputBuffer,
data->elapsedTime,
data->bitRate/1000);
if(ret == OUTPUT_BUFFER_DC_STOP) {
data->flush = 0;
return DECODE_BREAK;
}
......@@ -635,7 +645,7 @@ void initAudioFormatFromMp3DecodeData(mp3DecodeData * data, AudioFormat * af) {
int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
mp3DecodeData data;
MpdTag * tag;
MpdTag * tag = NULL;
if(openMp3FromInputStream(inStream, &data, dc, &tag) < 0) {
closeInputStream(inStream);
......@@ -659,7 +669,6 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
if(tag) freeMpdTag(tag);
tag = newMpdTag();
tag->title = strdup(inStream->metaTitle);
/* free ths now, so we know we are done with it */
free(inStream->metaTitle);
inStream->metaTitle = NULL;
if(inStream->metaName) {
......@@ -689,7 +698,7 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
while(mp3Read(&data,cb,dc)!=DECODE_BREAK);
/* send last little bit if not dc->stop */
if(data.outputPtr!=data.outputBuffer && data.flush) {
if(!dc->stop && data.outputPtr!=data.outputBuffer && data.flush) {
sendDataToOutputBuffer(cb, NULL, dc,
data.inStream->seekable,
data.outputBuffer,
......
......@@ -321,9 +321,8 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
ov_pcm_tell(&vf)/
dc->audioFormat.sampleRate,
bitRate);
if(dc->stop) break;
chunkpos = 0;
if(dc->stop) break;
}
}
......
......@@ -25,6 +25,11 @@
#include <sys/types.h>
#include <unistd.h>
void initInputStream() {
inputStream_initFile();
inputStream_initHttp();
}
int openInputStream(InputStream * inStream, char * url) {
inStream->offset = 0;
inStream->size = 0;
......
......@@ -49,6 +49,8 @@ struct _InputStream {
char * metaTitle;
};
void initInputStream();
int isUrlSaneForInputStream(char * url);
/* if an error occurs for these 3 functions, then -1 is returned and errno
......
......@@ -23,6 +23,9 @@
#include <unistd.h>
#include <errno.h>
void inputStream_initFile() {
}
int inputStream_fileOpen(InputStream * inStream, char * filename) {
FILE * fp;
......
......@@ -21,6 +21,8 @@
#include "inputStream.h"
void inputStream_initFile();
int inputStream_fileOpen(InputStream * inStream, char * filename);
int inputStream_fileSeek(InputStream * inStream, long offset, int whence);
......
......@@ -20,6 +20,7 @@
#include "utils.h"
#include "log.h"
#include "conf.h"
#include <stdio.h>
#include <sys/time.h>
......@@ -59,12 +60,145 @@ typedef struct _InputStreemHTTPData {
int icyMetaint;
int prebuffer;
int icyOffset;
char * proxyHost;
int proxyPort;
char * proxyAuth;
} InputStreamHTTPData;
void inputStream_initHttp() {
if(getConf()[CONF_HTTP_PROXY_HOST]) {
char * portStr = getConf()[CONF_HTTP_PROXY_PORT];
int port = 0;
char * test;
if(!portStr) {
ERROR("http_proxy_host specified but not the http_"
"proxy_port\n");
exit(EXIT_FAILURE);
}
port = strtol(portStr, &test, 10);
if(port <= 0 || *test != '\0') {
ERROR("http_proxy_port \"%s\" is not a positive integer"
"\n", portStr);
}
if(getConf()[CONF_HTTP_PROXY_USER] &&
!getConf()[CONF_HTTP_PROXY_PASSWORD])
{
ERROR("http_proxy_user specified, but not http_proxy_"
"password\n");
exit(EXIT_FAILURE);
}
if(getConf()[CONF_HTTP_PROXY_PASSWORD] &&
!getConf()[CONF_HTTP_PROXY_USER])
{
ERROR("http proxy password specified, but not http "
"proxy user\n");
exit(EXIT_FAILURE);
}
}
else if(getConf()[CONF_HTTP_PROXY_PORT]) {
ERROR("http_proxy_port specified but not http_proxy_host\n");
exit(EXIT_FAILURE);
}
else if(getConf()[CONF_HTTP_PROXY_USER]) {
ERROR("http_proxy_user specified but not http_proxy_host\n");
exit(EXIT_FAILURE);
}
else if(getConf()[CONF_HTTP_PROXY_PASSWORD]) {
ERROR("http_proxy_password specified but not http_proxy_host"
"\n");
exit(EXIT_FAILURE);
}
}
/* base64 code taken from xmms */
#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
static char * base64Dup(char * s) {
int i;
int len = strlen(s);
char * ret = calloc(BASE64_LENGTH(len)+1, 1);
unsigned char * p = (unsigned char *)ret;
char tbl[64] = {
'A','B','C','D','E','F','G','H',
'I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X',
'Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3',
'4','5','6','7','8','9','+','/'
};
/* Transform the 3x8 bits to 4x6 bits, as required by base64. */
for(i = 0; i < len; i += 3) {
*p++ = tbl[s[0] >> 2];
*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
*p++ = tbl[s[2] & 0x3f];
s += 3;
}
/* Pad the result if necessary... */
if (i == len + 1)
*(p - 1) = '=';
else if (i == len + 2)
*(p - 1) = *(p - 2) = '=';
/* ...and zero-terminate it. */
*p = '\0';
return ret;
}
#define PROXY_AUTH_HEADER "Proxy-Authorization: Basic "
static char * proxyAuthString(char * user, char * password) {
char * ret = NULL;
int templen;
char * temp;
char * temp64;
if(!user || !password) return NULL;
templen = strlen(user) + strlen(password) + 2;
temp = malloc(templen);
strcpy(temp, user);
strcat(temp, ":");
strcat(temp, password);
temp64 = base64Dup(temp);
free(temp);
ret = malloc(strlen(temp64)+strlen(PROXY_AUTH_HEADER)+3);
strcpy(ret, PROXY_AUTH_HEADER);
strcat(ret, temp64);
strcat(ret, "\r\n");
free(temp64);
return ret;
}
static InputStreamHTTPData * newInputStreamHTTPData() {
InputStreamHTTPData * ret = malloc(sizeof(InputStreamHTTPData));
ret->host = NULL;
if(getConf()[CONF_HTTP_PROXY_HOST]) {
ret->proxyHost = getConf()[CONF_HTTP_PROXY_HOST];
DEBUG(__FILE__ ": Proxy host %s\n", ret->proxyHost);
ret->proxyPort = atoi(getConf()[CONF_HTTP_PROXY_PORT]);
DEBUG(__FILE__ ": Proxy port %i\n", ret->proxyPort);
ret->proxyAuth = proxyAuthString(
getConf()[CONF_HTTP_PROXY_USER],
getConf()[CONF_HTTP_PROXY_PASSWORD]);
}
else {
ret->proxyHost = NULL;
ret->proxyAuth = NULL;
}
ret->host = NULL;
ret->path = NULL;
ret->port = 80;
ret->connState = HTTP_CONN_STATE_CLOSED;
......@@ -79,6 +213,7 @@ static InputStreamHTTPData * newInputStreamHTTPData() {
static void freeInputStreamHTTPData(InputStreamHTTPData * data) {
if(data->host) free(data->host);
if(data->path) free(data->path);
if(data->proxyAuth) free(data->proxyAuth);
free(data);
}
......@@ -120,7 +255,8 @@ static int parseUrl(InputStreamHTTPData * data, char * url) {
}
/* fetch the path */
data->path = strdup(slash ? slash : "/");
if(data->proxyHost) data->path = strdup(url);
else data->path = strdup(slash ? slash : "/");
return 0;
}
......@@ -133,17 +269,29 @@ static int initHTTPConnection(InputStream * inStream) {
InputStreamHTTPData * data = (InputStreamHTTPData *)inStream->data;
int flags;
int ret;
char * connHost;
int connPort;
#ifdef HAVE_IPV6
struct sockaddr_in6 sin6;
#endif
if(!(he = gethostbyname(data->host))) {
if(data->proxyHost) {
connHost = data->proxyHost;
connPort = data->proxyPort;
}
else {
connHost = data->host;
connPort = data->port;
}
if(!(he = gethostbyname(connHost))) {
DEBUG(__FILE__ ": failure to lookup host \"%s\"\n",connHost);
return -1;
}
memset(&sin,0,sizeof(struct sockaddr_in));
sin.sin_family = AF_INET;
sin.sin_port = htons(data->port);
sin.sin_port = htons(connPort);
#ifdef HAVE_IPV6
memset(&sin6,0,sizeof(struct sockaddr_in6));
sin6.sin6_family = AF_INET6;
......@@ -181,6 +329,7 @@ static int initHTTPConnection(InputStream * inStream) {
ret = connect(data->sock,dest,destlen);
if(ret < 0 && errno!=EINPROGRESS) {
DEBUG(__FILE__ ": unable to connect: %s\n", strerror(errno));
close(data->sock);
return -1;
}
......@@ -215,6 +364,7 @@ static int finishHTTPInit(InputStream * inStream) {
if(ret == 0 || (ret < 0 && errno==EINTR)) return 0;
if(ret < 0) {
DEBUG(__FILE__ ": problem select'ing: %s\n",strerror(errno));
close(data->sock);
data->connState = HTTP_CONN_STATE_CLOSED;
return -1;
......@@ -229,15 +379,18 @@ static int finishHTTPInit(InputStream * inStream) {
memset(request, 0, 2049);
/* deal with ICY metadata later, for now its fucking up stuff! */
snprintf(request, 2048, "GET %s HTTP/1.1\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"User-Agent: %s/%s\r\n"
"Range: bytes=%ld-\r\n"
"Icy-Metadata:1\r\n"
"\r\n",
data->path, data->host, "httpTest", "0.0.0",
inStream->offset);
snprintf(request, 2048, "GET %s HTTP/1.0\r\n"
"Host: %s\r\n"
/*"Connection: close\r\n"*/
"User-Agent: %s/%s\r\n"
/*"Range: bytes=%ld-\r\n"*/
"%s" /* authorization */
"Icy-Metadata:1\r\n"
"\r\n",
data->path, data->host, "httpTest", "0.0.0",
/*inStream->offset,*/
data->proxyAuth ? data->proxyAuth : "" );
ret = write(data->sock, request, strlen(request));
if(ret!=strlen(request)) {
......
......@@ -21,6 +21,8 @@
#include "inputStream.h"
void inputStream_initHttp();
int inputStream_httpOpen(InputStream * inStream, char * filename);
int inputStream_httpSeek(InputStream * inStream, long offset, int whence);
......
......@@ -38,4 +38,3 @@ int interfacePrintWithFD(int fd, char * buffer, int len);
int doIOForInterfaces();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -24,12 +24,12 @@
extern "C" {
# endif
# define FPM_INTEL
# define FPM_DEFAULT
# define SIZEOF_INT 4
# define SIZEOF_LONG 4
# define SIZEOF_LONG 8
# define SIZEOF_LONG_LONG 8
......
......@@ -190,14 +190,19 @@ int lsPlaylists(FILE * fp, char * utf8path) {
return 0;
}
int isFile(char * utf8file, time_t * mtime) {
struct stat st;
int myStat(char * utf8file, struct stat * st) {
char * file = utf8ToFsCharset(utf8file);
char * actualFile = file;
if(actualFile[0]!='/') actualFile = rmp2amp(file);
if(stat(actualFile,&st)==0) {
return stat(actualFile,st);
}
int isFile(char * utf8file, time_t * mtime) {
struct stat st;
if(myStat(utf8file,&st)==0) {
if(S_ISREG(st.st_mode)) {
if(mtime) *mtime = st.st_mtime;
return 1;
......@@ -233,57 +238,31 @@ int isPlaylist(char * utf8file) {
return 0;
}
int hasWaveSuffix(char * utf8file) {
return hasSuffix(utf8file,"wav");
}
int hasFlacSuffix(char * utf8file) {
return hasSuffix(utf8file,"flac");
}
int hasOggSuffix(char * utf8file) {
return hasSuffix(utf8file,"ogg");
}
int hasAacSuffix(char * utf8file) {
return hasSuffix(utf8file,"aac");
}
int hasMp4Suffix(char * utf8file) {
if(hasSuffix(utf8file,"mp4")) return 1;
if(hasSuffix(utf8file,"m4a")) return 1;
return 0;
}
int hasMp3Suffix(char * utf8file) {
return hasSuffix(utf8file,"mp3");
}
int isDir(char * utf8name) {
struct stat st;
if(stat(rmp2amp(utf8ToFsCharset(utf8name)),&st)==0) {
if(myStat(utf8name,&st)==0) {
if(S_ISDIR(st.st_mode)) {
return 1;
}
}
else {
DEBUG("isDir: unable to stat: %s (%s)\n",utf8name,
rmp2amp(utf8ToFsCharset(utf8name)));
}
return 0;
}
InputPlugin * isMusic(char * utf8file, time_t * mtime) {
InputPlugin * hasMusicSuffix(char * utf8file) {
InputPlugin * ret = NULL;
if(isFile(utf8file,mtime)) {
char * s = getSuffix(utf8file);
if(s) ret = getInputPluginFromSuffix(s);
}
char * s = getSuffix(utf8file);
if(s) ret = getInputPluginFromSuffix(s);
return ret;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
InputPlugin * isMusic(char * utf8file, time_t * mtime) {
if(isFile(utf8file,mtime)) {
return hasMusicSuffix(utf8file);
}
return NULL;
}
......@@ -24,6 +24,9 @@
#include "inputPlugin.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
int lsPlaylists(FILE * fp, char * utf8path);
......@@ -34,12 +37,16 @@ int isValidRemoteUtf8Url(char * utf8url);
int isRemoteUrl(char * url);
int myStat(char * utf8file, struct stat * st);
int isFile(char * utf8file, time_t * mtime);
int isDir(char * utf8name);
int isPlaylist(char * utf8file);
InputPlugin * hasMusicSuffix(char * utf8file);
InputPlugin * isMusic(char * utf8file, time_t * mtime);
char * dupAndStripPlaylistSuffix(char * file);
......@@ -47,4 +54,3 @@ char * dupAndStripPlaylistSuffix(char * file);
int printRemoteUrlHandlers(FILE * fp);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -34,6 +34,7 @@
#include "permission.h"
#include "replayGain.h"
#include "inputPlugin.h"
#include "inputStream.h"
#include "../config.h"
#include <stdio.h>
......@@ -205,17 +206,9 @@ void parseOptions(int argc, char ** argv, Options * options) {
void closeAllFDs() {
int i;
int fds = getdtablesize();
for(i=0;i<FD_SETSIZE;i++) {
switch(i) {
case STDIN_FILENO:
case STDOUT_FILENO:
case STDERR_FILENO:
break;
default:
close(i);
}
}
for(i = 3; i < fds; i++) close(i);
}
void establishListen(Options * options) {
......@@ -428,9 +421,6 @@ int main(int argc, char * argv[]) {
establishListen(&options);
/*
* lose privileges as early as possible
*/
changeToUser(&options);
openLogFiles(&options, &out, &err);
......@@ -451,6 +441,7 @@ int main(int argc, char * argv[]) {
initPlayerData();
initVolume();
initInterfaces();
initInputStream();
daemonize(&options);
......
......@@ -57,10 +57,11 @@ void clearOutputBuffer(OutputBuffer * cb) {
void flushOutputBuffer(OutputBuffer * cb) {
if(currentChunk == cb->end) {
cb->end++;
if(cb->end>=buffered_chunks) {
cb->end = 0;
int next = cb->end+1;
if(next>=buffered_chunks) {
next = 0;
}
cb->end = next;
currentChunk = -1;
}
}
......
......@@ -1049,7 +1049,7 @@ int moveSongInPlaylist(FILE * fp, int from, int to) {
moveSongFromTo(i-1, i);
}
/* put song at _to_ */
playlist.idToNum[playlist.numToId[tmpId]] = to;
playlist.idToNum[tmpId] = to;
playlist.numToId[to] = tmpId;
playlist.songs[to] = tmpSong;
playlist.songMod[to] = playlist.version;
......
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