Commit a953cd9b authored by Led's avatar Led

0.12.0.20041109

parent a8b2361b
ver 0.11.5 (2004/11/1a
1) New id3v1_ecnoding config option to configure the id3v1 tag encoding (patch from dottemag)
2) Strip '\r' from m3u playlists (thank you windows)
3) Use random() instead of rand() for playlist randomizing
4) Fix a bug trying skipping some commented lines in m3u playlist files
5) Fix a bug when fetching metadata from streams that may cause certain weirdnesses
6) Fix a bug where replaygain preamp was used on files w/o replaygain tags
7) Fix a busy loop when trying to prebuffer a nonexistant or missing stream
8) Fix a bug in forgetting to remove leading ' ' in content-type for http streams
9) Check for ice-name in http headers
10) Be sure the strip all '\n' chars in tags
11) Set $HOME env variable when setuid'ing, this should fix the /root/.mcop errors triggered by arts/libao
ver 0.11.4 (2004/7/26)
1) Fixed a segfault when decoding mp3's with corrupt id3v2 tags
2) Fixed a memory leak when encountering id3v2 tags in mp3 decoder
......
0.12
----
*) AudioOutput
*) have "format" as a default config option for all audioOutputs
*) don't automatically close audioOutput devices on openDevice(),
instead, let the plugins determine if they should be closed
or not, so that they can just leave the device open,
like if they are using a constant audioFormat
*) add genre and date metadata
*) Fix id3v1 encoding
*) Cleanup Config File Code
*) Steal resampling code from ices (i think this code works only for 16-bit)
*) Rewrite replaygain stuff:
*) Replay gain struct with album and track gain's and peak's
*) Pass these to replaygain function
*) Don't have deocder plugins inquire weather or not to use replaygain,
they should just parse tags and pass these to replaygain func
*) If replaygain tag info present, average the replaygain gain's
and peak's on the fly
*) If NULL replaygain struct, then use the average replaygain gains
and peak's to compute the the scale for files missing
replaygain tags (make this a config file option)
*) Optimize read() on clients
*) Add libshout && vorbis encoding support
*) clean up code to make more robust (only works for 16-bits)
*) cleanup configure script stuff (shout needs vorbisenc)
*) add command
*) command that takes file/url's (no directory's) and returns the songid
*) allow to specify position in playlist where to insert song(s)
*) add support for coverart using freedesktop standard for icons/images
*) rewrite saved playlist code
*) abstract out saved playlists from playlist.c
*) command for displaying playlist contents
*) command for appending to playlist
*) new commands
*) clear <playlist> /* synonym for rm */
*) add <playlist> <path>
*) playlist <playlist> /* displays saved playlist */
*) replace <playlist> /* replace current playlist
with saved playlist and
keep playing */
*) state
*) abstract out state code from playlist.c
*) save states of audioOutput devices
*) put MPD Version in statefile
*) add command for inserting songs in a specific position
*) put more debugging info when failing to read/write db and other similar
errors
*) max http buffering configurable
*) make libao optional during configure, but check that some form of audioOutput
is enabled (either oss, shout, or ao)
*) use getaddrinfo instead of gethostbyname (check libshout)
*) Fix id3v1 encoding
Post-1.0
--------
*) crosslink "list" stuff, for example, artists are crosslinked to alubms and
vice versa, this way you can do list album artists or list artist albums, this
will make life easier when we add genre and other metadata
*) Cleanup Config File Code
*) rewrite linked list impelmentation to be more flexible
*) remove "key" stuff
*) allow assigning a compare function for a list
*) Optimize read() on clients
*) allow find/search commands take arbitrary search pairs
*) add configurable metadata, and add newmetadata items
0.13
----
*) support for dynamically loading plugins
*) rewrite metadata/db handling
*) store all metadata entries in table
*) each contains a counter reference
*) new MpdDBTag, which instead of strings allocated for each metadata
entry, store a char * string to the metadata entry in the table
*) multiple artist support
*) multiple genre support {char *, int pairs for each metadata entry
indicating the type of metadata and its value)
*) MpdDBTag <-> MpdTag interface
......@@ -22056,6 +22056,13 @@ rm -f conftest*
fi
if test x$enable_ao = xyes; then
if test x$enable_ogg = xno; then
{ echo "$as_me:$LINENO: WARNING: \"disabling shout streaming support since vorbis was not found\"" >&5
echo "$as_me: WARNING: \"disabling shout streaming support since vorbis was not found\"" >&2;}
fi
fi
if test x$enable_ao = xyes; then
# Check whether --with-ao or --without-ao was given.
if test "${with_ao+set}" = set; then
......
......@@ -102,6 +102,12 @@ AP_maGiC_VALUE
fi
if test x$enable_ao = xyes; then
if test x$enable_ogg = xno; then
AC_MSG_WARN("disabling shout streaming support since vorbis was not found")
fi
fi
if test x$enable_ao = xyes; then
XIPH_PATH_AO(MPD_LIBS="$MPD_LIBS $AO_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AO_CFLAGS",AC_MSG_ERROR(Must have libao installed!!!))
AC_DEFINE(HAVE_AUDIO, 1, [Define to play audio])
fi
......
......@@ -76,10 +76,16 @@ audio_output {
# name "my cool stream"
# host "hostname"
# port "8000"
# user "source"
# mount "/mpd.ogg"
# password "hackme"
# quality "5.0"
# quality "5.0"
# bitrate "128"
# format "44100:16:1"
#
# Optional Paramters
# user "source"
# description "here's my long descriptiion"
# genre "jazz"
#} # end of audio_output
#
##########################################################
......
bin_PROGRAMS = mpd
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR) $(MP4FF_SUBDIR)
mpd_audioOutputs = \
audioOutputs/audioOutput_ao.c \
audioOutputs/audioOutput_oss.c \
audioOutputs/audioOutput_shout.c
mpd_inputPlugins = \
inputPlugins/aac_plugin.c \
inputPlugins/audiofile_plugin.c \
......@@ -54,12 +59,10 @@ mpd_headers = \
mpd_SOURCES = \
$(mpd_headers) \
$(mpd_audioOutputs) \
$(mpd_inputPlugins) \
audio.c \
audioOutput.c \
audioOutput_ao.c \
audioOutput_oss.c \
audioOutput_shout.c \
buffer2array.c \
charConv.c \
command.c \
......
......@@ -21,6 +21,8 @@
#include "conf.h"
#include "log.h"
#include "sig_handlers.h"
#include "command.h"
#include "playerData.h"
#include <stdlib.h>
#include <string.h>
......@@ -31,20 +33,34 @@ static AudioFormat audio_format;
static AudioFormat * audio_configFormat = NULL;
static AudioOutput ** audioOutputArray = NULL;
static mpd_uint8 audioOutputArraySize = 0;
/* the audioEnabledArray should be stuck into shared memory, and then disable
and enable in playAudio() routine */
static mpd_sint8 * pdAudioDevicesEnabled = NULL;
static mpd_sint8 myAudioDevicesEnabled[AUDIO_MAX_DEVICES];
static mpd_uint8 audioOpened = 0;
static mpd_sint32 audioBufferSize = 0;
static char * audioBuffer = NULL;
static mpd_sint32 audioBufferPos = 0;
void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
if(!src) return;
dest->sampleRate = src->sampleRate;
dest->bits = src->bits;
dest->channels = src->channels;
memcpy(dest, src, sizeof(AudioFormat));
}
static AudioOutput ** audioOutputArray = NULL;
static int audioOutputArraySize = 0;
int cmpAudioFormat(AudioFormat * f1, AudioFormat * f2) {
return memcmp(f1, f2, sizeof(AudioFormat));
}
extern AudioOutputPlugin aoPlugin;
extern AudioOutputPlugin shoutPlugin;
extern AudioOutputPlugin ossPlugin;
/* make sure initPlayerData is called before this function!! */
void initAudioDriver() {
ConfigParam * param = NULL;
int i;
......@@ -52,8 +68,22 @@ void initAudioDriver() {
initAudioOutputPlugins();
loadAudioOutputPlugin(&aoPlugin);
loadAudioOutputPlugin(&shoutPlugin);
loadAudioOutputPlugin(&ossPlugin);
pdAudioDevicesEnabled = (getPlayerData())->audioDeviceEnabled;
for(i = 0; i < AUDIO_MAX_DEVICES; i++) {
pdAudioDevicesEnabled[i] = 1;
myAudioDevicesEnabled[i] = 1;
}
while((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param))) {
if(audioOutputArraySize == AUDIO_MAX_DEVICES) {
ERROR("only up to 255 audio output devices are "
"supported");
exit(EXIT_FAILURE);
}
i = audioOutputArraySize++;
audioOutputArray = realloc(audioOutputArray,
......@@ -177,62 +207,123 @@ void finishAudioDriver() {
int isCurrentAudioFormat(AudioFormat * audioFormat) {
if(!audioFormat) return 1;
if(memcmp(audioFormat,&audio_format,sizeof(AudioFormat)) != 0) return 0;
if(cmpAudioFormat(audioFormat, &audio_format) != 0) return 0;
return 1;
}
int openAudioDevice(AudioFormat * audioFormat) {
int isCurrentFormat = isCurrentAudioFormat(audioFormat);
inline void syncAudioDevicesEnabledArrays() {
int i;
memcpy(myAudioDevicesEnabled, pdAudioDevicesEnabled,AUDIO_MAX_DEVICES);
for(i = 0; i < audioOutputArraySize; i++) {
if(myAudioDevicesEnabled[i]) {
openAudioOutput(audioOutputArray[i], &audio_format);
}
else closeAudioOutput(audioOutputArray[i]);
}
}
static int flushAudioBuffer() {
int ret = -1;
int i;
if(!audioOutputArray) return -1;
if(audioBufferPos == 0) return 0;
if(!isCurrentFormat) {
copyAudioFormat(&audio_format, audioFormat);
if(0 != memcmp(pdAudioDevicesEnabled, myAudioDevicesEnabled,
AUDIO_MAX_DEVICES))
{
syncAudioDevicesEnabledArrays();
}
for(i = 0; i < audioOutputArraySize; i++) {
if(!audioOutputArray[i]->open || !isCurrentFormat) {
openAudioOutput(audioOutputArray[i], &audio_format);
if(!myAudioDevicesEnabled[i]) continue;
if(0 == playAudioOutput(audioOutputArray[i], audioBuffer,
audioBufferPos))
{
ret = 0;
}
if(audioOutputArray[i]->open) ret = 0;
}
audioBufferPos = 0;
return ret;
}
int playAudio(char * playChunk, int size) {
int openAudioDevice(AudioFormat * audioFormat) {
int isCurrentFormat = isCurrentAudioFormat(audioFormat);
int ret = -1;
int i;
if(!audioOutputArray) return -1;
if(!audioOpened || !isCurrentFormat) {
flushAudioBuffer();
copyAudioFormat(&audio_format, audioFormat);
audioBufferSize = (audio_format.bits >> 3)*
audio_format.channels;
audioBufferSize*= audio_format.sampleRate >> 5;
audioBuffer = realloc(audioBuffer, audioBufferSize);
}
syncAudioDevicesEnabledArrays();
for(i = 0; i < audioOutputArraySize; i++) {
if(0 == playAudioOutput(audioOutputArray[i], playChunk, size)) {
ret = 0;
if(audioOutputArray[i]->open) ret = 0;
}
if(ret == 0) audioOpened = 1;
else {
/* close all devices if there was an error */
for(i = 0; i < audioOutputArraySize; i++) {
closeAudioOutput(audioOutputArray[i]);
}
audioOpened = 0;
}
return ret;
}
int isAudioDeviceOpen() {
int ret = 0;
int i;
int playAudio(char * playChunk, int size) {
int send;
while(size > 0) {
send = audioBufferSize-audioBufferPos;
send = send < size ? send : size;
for(i = 0; i < audioOutputArraySize; i++) {
ret |= audioOutputArray[i]->open;
memcpy(audioBuffer+audioBufferPos, playChunk, send);
audioBufferPos += send;
size -= send;
playChunk+= send;
if(audioBufferPos == audioBufferSize) {
if( flushAudioBuffer() < 0 ) return -1;
}
}
return ret;
return 0;
}
int isAudioDeviceOpen() {
return audioOpened;
}
void closeAudioDevice() {
int i;
flushAudioBuffer();
free(audioBuffer);
audioBuffer = NULL;
audioBufferSize = 0;
for(i = 0; i < audioOutputArraySize; i++) {
closeAudioOutput(audioOutputArray[i]);
}
audioOpened = 0;
}
void sendMetadataToAudioDevice(MpdTag * tag) {
......@@ -242,3 +333,38 @@ void sendMetadataToAudioDevice(MpdTag * tag) {
sendMetadataToAudioOutput(audioOutputArray[i], tag);
}
}
int enableAudioDevice(FILE * fp, int device) {
if(device < 0 || device >= audioOutputArraySize) {
commandError(fp, ACK_ERROR_ARG, "audio output device id %i "
"doesn't exist\n", device);
return -1;
}
pdAudioDevicesEnabled[device] = 1;
return 0;
}
int disableAudioDevice(FILE * fp, int device) {
if(device < 0 || device >= audioOutputArraySize) {
commandError(fp, ACK_ERROR_ARG, "audio output device id %i "
"doesn't exist\n", device);
return -1;
}
pdAudioDevicesEnabled[device] = 0;
return 0;
}
void printAudioDevices(FILE * fp) {
int i;
for(i = 0; i < audioOutputArraySize; i++) {
myfprintf(fp, "deviceid: %i\n", i);
myfprintf(fp, "devicename: %s\n", audioOutputArray[i]->name);
myfprintf(fp, "deviceenabled: %i\n",
(int)pdAudioDevicesEnabled[i]);
}
}
......@@ -28,6 +28,8 @@
#define AUDIO_AO_DRIVER_DEFAULT "default"
#define AUDIO_MAX_DEVICES 8
typedef struct _AudioFormat {
volatile mpd_sint8 channels;
volatile mpd_uint32 sampleRate;
......@@ -36,10 +38,13 @@ typedef struct _AudioFormat {
void copyAudioFormat(AudioFormat * dest, AudioFormat * src);
int cmpAudioFormat(AudioFormat * dest, AudioFormat * src);
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
int parseAudioConfig(AudioFormat * audioFormat, char * conf);
/* make sure initPlayerData is called before this function!! */
void initAudioConfig();
void finishAudioConfig();
......@@ -60,4 +65,12 @@ int isCurrentAudioFormat(AudioFormat * audioFormat);
void sendMetadataToAudioDevice(MpdTag * tag);
/* these functions are called in the main parent process while the child
process is busy playing to the audio */
int enableAudioDevice(FILE * fp, int device);
int disableAudioDevice(FILE * fp, int device);
void printAudioDevices(FILE * fp);
#endif
......@@ -2,11 +2,13 @@
#include "list.h"
#include "log.h"
#include "pcm_utils.h"
#include <string.h>
#define AUDIO_OUTPUT_TYPE "type"
#define AUDIO_OUTPUT_NAME "name"
#define AUDIO_OUTPUT_FORMAT "format"
static List * audioOutputPluginList;
......@@ -29,26 +31,27 @@ void finishAudioOutputPlugins() {
freeList(audioOutputPluginList);
}
#define getBlockParam(name, str) { \
BlockParam * bp; \
#define getBlockParam(name, str, force) { \
bp = getBlockParam(param, name); \
if(bp == NULL) { \
if(force && bp == NULL) { \
ERROR("couldn't find parameter \"%s\" in audio output " \
"definition begining at %i\n", \
name, param->line); \
exit(EXIT_FAILURE); \
} \
str = bp->value; \
if(bp) str = bp->value; \
}
AudioOutput * newAudioOutput(ConfigParam * param) {
AudioOutput * ret = NULL;
void * data = NULL;
char * name = NULL;
char * format = NULL;
char * type = NULL;
BlockParam * bp;
getBlockParam(AUDIO_OUTPUT_NAME, name);
getBlockParam(AUDIO_OUTPUT_TYPE, type);
getBlockParam(AUDIO_OUTPUT_NAME, name, 1);
getBlockParam(AUDIO_OUTPUT_TYPE, type, 1);
if(findInList(audioOutputPluginList, type, &data)) {
AudioOutputPlugin * plugin = (AudioOutputPlugin *) data;
......@@ -62,6 +65,27 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
ret->sendMetdataFunc = plugin->sendMetdataFunc;
ret->open = 0;
ret->convertAudioFormat = 0;
ret->sameInAndOutFormats = 0;
ret->convBuffer = NULL;
ret->convBufferLen = 0;
memset(&ret->inAudioFormat, 0, sizeof(AudioFormat));
memset(&ret->outAudioFormat, 0, sizeof(AudioFormat));
getBlockParam(AUDIO_OUTPUT_FORMAT, format, 0);
if(format) {
ret->convertAudioFormat = 1;
if(0 != parseAudioConfig(&ret->outAudioFormat, format))
{
ERROR("error parsing format at line %i\n",
bp->line);
exit(EXIT_FAILURE);
}
}
if(plugin->initDriverFunc(ret, param) != 0) {
free(ret);
ret = NULL;
......@@ -69,7 +93,7 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
}
else {
ERROR("couldn't find audio output plugin for type \"%s\" at "
"line %i", type, param->line);
"line %i\n", type, param->line);
exit(EXIT_FAILURE);
}
......@@ -77,13 +101,68 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
}
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat) {
if(audioOutput->open) closeAudioOutput(audioOutput);
if(audioOutput->open) {
if(cmpAudioFormat(audioFormat, &audioOutput->inAudioFormat)
== 0)
{
return 0;
}
closeAudioOutput(audioOutput);
}
copyAudioFormat(&audioOutput->inAudioFormat, audioFormat);
if(audioOutput->convertAudioFormat) {
if(cmpAudioFormat(&audioOutput->inAudioFormat,
&audioOutput->outAudioFormat) == 0)
{
audioOutput->sameInAndOutFormats = 1;
}
else audioOutput->sameInAndOutFormats = 0;
}
else {
audioOutput->sameInAndOutFormats = 1;
copyAudioFormat(&audioOutput->outAudioFormat,
&audioOutput->inAudioFormat);
}
return audioOutput->openDeviceFunc(audioOutput, audioFormat);
}
static void convertAudioFormat(AudioOutput * audioOutput, char ** chunkArgPtr,
int * sizeArgPtr)
{
int size = pcm_sizeOfOutputBufferForAudioFormatConversion(
&(audioOutput->inAudioFormat), *sizeArgPtr,
&(audioOutput->outAudioFormat));
if(size > audioOutput->convBufferLen) {
audioOutput->convBuffer =
realloc(audioOutput->convBuffer, size);
audioOutput->convBufferLen = size;
}
pcm_convertAudioFormat(&(audioOutput->inAudioFormat), *chunkArgPtr,
*sizeArgPtr, &(audioOutput->outAudioFormat),
audioOutput->convBuffer);
*sizeArgPtr = size;
*chunkArgPtr = audioOutput->convBuffer;
}
int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size) {
int ret;
if(!audioOutput->open) return -1;
return audioOutput->playFunc(audioOutput, playChunk, size);
if(!audioOutput->sameInAndOutFormats) {
convertAudioFormat(audioOutput, &playChunk, &size);
}
ret = audioOutput->playFunc(audioOutput, playChunk, size);
return ret;
}
void closeAudioOutput(AudioOutput * audioOutput) {
......@@ -93,6 +172,7 @@ void closeAudioOutput(AudioOutput * audioOutput) {
void finishAudioOutput(AudioOutput * audioOutput) {
closeAudioOutput(audioOutput);
audioOutput->finishDriverFunc(audioOutput);
if(audioOutput->convBuffer) free(audioOutput->convBuffer);
free(audioOutput->type);
free(audioOutput->name);
free(audioOutput);
......
......@@ -26,8 +26,6 @@
#include "tag.h"
#include "conf.h"
#define AUDIO_AO_DRIVER_DEFAULT "default"
typedef struct _AudioOutput AudioOutput;
typedef int (* AudioOutputInitDriverFunc) (AudioOutput * audioOutput,
......@@ -57,6 +55,13 @@ struct _AudioOutput {
AudioOutputCloseDeviceFunc closeDeviceFunc;
AudioOutputSendMetadataFunc sendMetdataFunc;
int convertAudioFormat;
AudioFormat inAudioFormat;
AudioFormat outAudioFormat;
char * convBuffer;
int convBufferLen;
int sameInAndOutFormats;
void * data;
};
......
......@@ -16,10 +16,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "audioOutput.h"
#include "conf.h"
#include "log.h"
#include "sig_handlers.h"
#include "../audioOutput.h"
#include "../conf.h"
#include "../log.h"
#include <string.h>
#include <assert.h>
......@@ -106,6 +105,9 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
exit(EXIT_FAILURE);
}
DEBUG("using ao driver \"%s\" for \"%s\"\n", ai->short_name,
audioOutput->name);
blockParam = getBlockParam(param, "options");
if(blockParam) {
......@@ -170,10 +172,8 @@ static void audioOutputAo_closeDevice(AudioOutput * audioOutput) {
AoData * ad = (AoData *) audioOutput->data;
if(ad->device) {
blockSignals();
ao_close(ad->device);
ad->device = NULL;
unblockSignals();
}
audioOutput->open = 0;
......@@ -194,9 +194,7 @@ static int audioOutputAo_openDevice(AudioOutput * audioOutput,
format.byte_format = AO_FMT_NATIVE;
format.channels = audioFormat->channels;
blockSignals();
ad->device = ao_open_live(ad->driverId, &format, ad->options);
unblockSignals();
if(ad->device==NULL) return -1;
......
......@@ -18,16 +18,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../config.h"
#include "audioOutput.h"
#include "../audioOutput.h"
#include <stdlib.h>
#ifdef HAVE_OSS
#include "conf.h"
#include "log.h"
#include "sig_handlers.h"
#include "../conf.h"
#include "../log.h"
#include "../sig_handlers.h"
#include <string.h>
#include <assert.h>
......@@ -75,11 +74,13 @@ static int oss_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
if(!bp) {
int fd;
if(0 <= (fd = open("/dev/sound/dsp", O_WRONLY | O_NONBLOCK))) {
if(0 <= (fd = open("/dev/sound/dsp", O_WRONLY))) {
od->device = strdup("/dev/sound/dsp");
close(fd);
}
else if(0 <= (fd = open("/dev/dsp", O_WRONLY | O_NONBLOCK))) {
else if(0 <= (fd = open("/dev/dsp", O_WRONLY))) {
od->device = strdup("/dev/dsp");
close(fd);
}
else {
ERROR("Error trying to open default OSS device "
......@@ -89,7 +90,6 @@ static int oss_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
exit(EXIT_FAILURE);
}
close(od->fd);
od->fd = -1;
return 0;
......
......@@ -120,4 +120,3 @@ void freeArgArray(char ** array, int argArrayLength) {
}
free(array);
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -26,4 +26,3 @@ int buffer2array(char * buffer, char *** array);
void freeArgArray(char ** array, int argArrayLength);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -147,4 +147,3 @@ void closeCharSetConversion() {
char_conv_use_iconv = 0;
}
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -28,4 +28,3 @@ char * convStrDup(char * string);
void closeCharSetConversion();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -45,6 +45,7 @@
#define COMMAND_KILL "kill"
#define COMMAND_CLOSE "close"
#define COMMAND_ADD "add"
#define COMMAND_ADDID "addid"
#define COMMAND_DELETE "delete"
#define COMMAND_DELETEID "deleteid"
#define COMMAND_PLAYLIST "playlist"
......@@ -82,6 +83,10 @@
#define COMMAND_URL_HANDLERS "urlhandlers"
#define COMMAND_PLCHANGES "plchanges"
#define COMMAND_CURRENTSONG "currentsong"
#define COMMAND_ENABLE_DEV "enabledevice"
#define COMMAND_DISABLE_DEV "disabledevice"
#define COMMAND_DEVICES "devices"
#define COMMAND_COMMANDS "commands"
#define COMMAND_STATUS_VOLUME "volume"
#define COMMAND_STATUS_STATE "state"
......@@ -295,11 +300,17 @@ int handleAdd(FILE * fp, unsigned int * permission, int argArrayLength,
if(argArrayLength == 2) {
path = argArray[1];
if(isRemoteUrl(path)) return addToPlaylist(fp,path);
if(isRemoteUrl(path)) return addToPlaylist(fp, path, 0);
}
return addAllIn(fp,path);
}
int handleAddId(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
return addToPlaylist(fp, argArray[0], 1);
}
int handleDelete(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
......@@ -756,6 +767,66 @@ int handleCrossfade(FILE * fp, unsigned int * permission, int argArrayLength,
return 0;
}
int handleEnableDevice(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
int device;
char * test;
device = strtol(argArray[1],&test,10);
if(*test!='\0' || device<0) {
commandError(fp, ACK_ERROR_ARG,
"\"%s\" is not a integer >= 0", argArray[1]);
return -1;
}
return enableAudioDevice(fp, device);
}
int handleDisableDevice(FILE * fp, unsigned int * permission,
int argArrayLength, char ** argArray)
{
int device;
char * test;
device = strtol(argArray[1],&test,10);
if(*test!='\0' || device<0) {
commandError(fp, ACK_ERROR_ARG,
"\"%s\" is not a integer >= 0", argArray[1]);
return -1;
}
return disableAudioDevice(fp, device);
}
int handleDevices(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
printAudioDevices(fp);
return 0;
}
/* don't be fooled, this is the command handler for "commands" command */
int handleCommands(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray)
{
ListNode * node = commandList->firstNode;
CommandEntry * cmd;
while(node != NULL) {
cmd = (CommandEntry *) node->data;
if(*permission & cmd->reqPermission) {
myfprintf(fp, "command: %s\n", cmd->cmd);
}
node = node->nextNode;
}
return 0;
}
void initCommands() {
commandList = makeList(free);
......@@ -768,6 +839,7 @@ void initCommands() {
addCommand(COMMAND_KILL ,PERMISSION_ADMIN, -1,-1,handleKill,NULL);
addCommand(COMMAND_CLOSE ,0, -1,-1,handleClose,NULL);
addCommand(COMMAND_ADD ,PERMISSION_ADD, 0, 1,handleAdd,NULL);
addCommand(COMMAND_ADDID ,PERMISSION_ADD, 0, 1,handleAddId,NULL);
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);
......@@ -804,6 +876,10 @@ void initCommands() {
addCommand(COMMAND_CROSSFADE ,PERMISSION_CONTROL, 1, 1,handleCrossfade,NULL);
addCommand(COMMAND_URL_HANDLERS,PERMISSION_READ, 0, 0,handleUrlHandlers,NULL);
addCommand(COMMAND_PLCHANGES ,PERMISSION_READ, 1, 1,handlePlaylistChanges,NULL);
addCommand(COMMAND_ENABLE_DEV ,PERMISSION_ADMIN, 1, 1,handleEnableDevice,NULL);
addCommand(COMMAND_DISABLE_DEV ,PERMISSION_ADMIN, 1, 1,handleDisableDevice,NULL);
addCommand(COMMAND_DEVICES ,PERMISSION_ADMIN, 0, 0,handleDevices,NULL);
addCommand(COMMAND_COMMANDS ,0, 0, 0,handleCommands,NULL);
sortList(commandList);
}
......
......@@ -31,6 +31,7 @@
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <errno.h>
#define MAX_STRING_SIZE MAXPATHLEN+80
......@@ -146,6 +147,8 @@ void initConf() {
registerConfigParam(CONF_HTTP_PROXY_PORT, 0, 0);
registerConfigParam(CONF_HTTP_PROXY_USER, 0, 0);
registerConfigParam(CONF_HTTP_PROXY_PASSWORD, 0, 0);
registerConfigParam(CONF_HTTP_BUFFER_SIZE, 0, 0);
registerConfigParam(CONF_HTTP_PREBUFFER_SIZE, 0, 0);
registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0);
registerConfigParam(CONF_ID3V1_ENCODING, 0, 0);
}
......@@ -191,7 +194,7 @@ static ConfigParam * readConfigBlock(FILE * fp, int * count, char * string) {
}
if(2 != argsMinusComment) {
ERROR("improperly formated config file at line %i:"
ERROR("improperly formatted config file at line %i:"
" %s\n", *count, string);
exit(EXIT_FAILURE);
}
......@@ -201,7 +204,7 @@ static ConfigParam * readConfigBlock(FILE * fp, int * count, char * string) {
0 == strcmp(array[0], CONF_BLOCK_END) ||
0 == strcmp(array[1], CONF_BLOCK_END))
{
ERROR("improperly formated config file at line %i:"
ERROR("improperly formatted config file at line %i:"
" %s\n", count, string);
ERROR("in block begging at line %i\n", ret->line);
exit(EXIT_FAILURE);
......@@ -228,7 +231,8 @@ void readConf(char * file) {
ConfigParam * param;
if(!(fp=fopen(file,"r"))) {
ERROR("problems opening file %s for reading\n",file);
ERROR("problems opening file %s for reading: %s\n", file,
strerror(errno));
exit(EXIT_FAILURE);
}
......@@ -246,7 +250,7 @@ void readConf(char * file) {
if(0 == argsMinusComment) continue;
if(2 != argsMinusComment) {
ERROR("improperly formated config file at line %i:"
ERROR("improperly formatted config file at line %i:"
" %s\n", count, string);
exit(EXIT_FAILURE);
}
......@@ -271,7 +275,7 @@ void readConf(char * file) {
if(entry->mask & CONF_BLOCK_MASK) {
if(0 != strcmp(array[1], CONF_BLOCK_BEGIN)) {
ERROR("improperly formated config file at "
ERROR("improperly formatted config file at "
"line %i: %s\n", count, string);
exit(EXIT_FAILURE);
}
......
......@@ -47,13 +47,15 @@
#define CONF_PASSWORD "password"
#define CONF_DEFAULT_PERMS "default_permissions"
#define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size"
#define CONF_REPLAYGAIN "replaygain"
#define CONF_AUDIO_OUTPUT_FORMAT "audio_output_format"
#define CONF_REPLAYGAIN "replaygain"
#define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
#define CONF_HTTP_PROXY_HOST "http_proxy_host"
#define CONF_HTTP_PROXY_PORT "http_proxy_port"
#define CONF_HTTP_PROXY_USER "http_proxy_user"
#define CONF_HTTP_PROXY_PASSWORD "http_proxy_password"
#define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
#define CONF_HTTP_BUFFER_SIZE "http_buffer_size"
#define CONF_HTTP_PREBUFFER_SIZE "http_prebuffer_size"
#define CONF_ID3V1_ENCODING "id3v1_encoding"
typedef struct _BlockParam {
......
......@@ -115,7 +115,7 @@ int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
MAXPATHLEN); \
pc->erroredUrl[MAXPATHLEN] = '\0'; \
pc->error = PLAYER_ERROR_AUDIO; \
ERROR("problems opening audio device while playing \"%s\"", pc->utf8url); \
ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \
quitDecode(pc,dc); \
return; \
} \
......@@ -237,7 +237,7 @@ int decodeSeek(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
MAXPATHLEN); \
pc->erroredUrl[MAXPATHLEN] = '\0'; \
pc->error = PLAYER_ERROR_AUDIO; \
ERROR("problems opening audio device while playing \"%s\"", pc->utf8url); \
ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \
quitDecode(pc,dc); \
return; \
} \
......
......@@ -66,4 +66,3 @@ void decodeSigHandler(int sig);
void decode();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -193,7 +193,7 @@ int updateInit(FILE * fp, List * pathList) {
unblockSignals();
finishSigHandlers();
close(listenSocket);
closeAllListenSockets();
freeAllInterfaces();
finishPlaylist();
finishVolume();
......@@ -1289,7 +1289,7 @@ int printAllIn(FILE * fp, char * name) {
}
int directoryAddSongToPlaylist(FILE * fp, Song * song, void * data) {
return addSongToPlaylist(fp,song);
return addSongToPlaylist(fp, song, 0);
}
int addAllIn(FILE * fp, char * name) {
......
......@@ -70,4 +70,3 @@ Song * getSongFromDB(char * file);
time_t getDbModTime();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -362,7 +362,7 @@ int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
sampleBufferLen = sampleCount*2;
sendDataToOutputBuffer(cb, NULL, dc, 0, sampleBuffer,
sampleBufferLen, time, bitRate);
sampleBufferLen, time, bitRate, NULL);
if(dc->seek) {
dc->seekError = 1;
dc->seek = 0;
......
......@@ -116,7 +116,8 @@ int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
ret*fs,
(float)current /
(float)dc->audioFormat.sampleRate,
bitRate);
bitRate,
NULL);
if(dc->stop) break;
}
}
......
......@@ -44,8 +44,8 @@ typedef struct {
OutputBuffer * cb;
DecoderControl * dc;
InputStream inStream;
float replayGainScale;
char * path;
ReplayGainInfo * replayGainInfo;
} FlacData;
/* this code is based on flac123, from flac-tools */
......@@ -82,7 +82,7 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc, char * path) {
data.bitRate = 0;
data.cb = cb;
data.dc = dc;
data.replayGainScale = 1.0;
data.replayGainInfo = NULL;
data.path = path;
if(openInputStream(&(data.inStream), path)<0) {
......@@ -195,6 +195,8 @@ int flac_decode(OutputBuffer * cb, DecoderControl *dc, char * path) {
else dc->state = DECODE_STATE_STOP;
fail:
if(data.replayGainInfo) freeReplayGainInfo(data.replayGainInfo);
if(streamOpen) closeInputStream(&(data.inStream));
if(flacDec) FLAC__seekable_stream_decoder_delete(flacDec);
......@@ -338,30 +340,28 @@ int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block, char * cmnt,
/* replaygain stuff by AliasMrJones */
void flacParseReplayGain(const FLAC__StreamMetadata *block, FlacData * data) {
int found;
float gain = 0.0;
float peak = 0.0;
int state = getReplayGainState();
if(NULL == data->replayGainInfo) {
freeReplayGainInfo(data->replayGainInfo);
data->replayGainInfo = NULL;
}
if(state == REPLAYGAIN_OFF) return;
data->replayGainInfo = newReplayGainInfo();
found = flacFindVorbisCommentFloat(block,"replaygain_album_gain",&gain);
if(found) {
flacFindVorbisCommentFloat(block,"replaygain_album_peak",
&peak);
}
int found = 0;
if(!found || state == REPLAYGAIN_TRACK) {
found = flacFindVorbisCommentFloat(block,
"replaygain_track_gain", &gain);
if(found) {
peak = 0.0;
flacFindVorbisCommentFloat(block,
"replaygain_track_peak",&peak);
}
}
found &= flacFindVorbisCommentFloat(block,"replaygain_album_gain",
&data->replayGainInfo->albumGain);
found &= flacFindVorbisCommentFloat(block,"replaygain_album_peak",
&data->replayGainInfo->albumPeak);
found &= flacFindVorbisCommentFloat(block,"replaygain_track_gain",
&data->replayGainInfo->trackGain);
found &= flacFindVorbisCommentFloat(block,"replaygain_track_peak",
&data->replayGainInfo->trackPeak);
if(found) data->replayGainScale = computeReplayGainScale(gain,peak);
if(!found) {
freeReplayGainInfo(data->replayGainInfo);
data->replayGainInfo = NULL;
}
}
void flacMetadata(const FLAC__SeekableStreamDecoder *dec,
......@@ -391,11 +391,9 @@ void flacMetadata(const FLAC__SeekableStreamDecoder *dec,
}
int flacSendChunk(FlacData * data) {
doReplayGain(data->chunk,data->chunk_length,&(data->dc->audioFormat),
data->replayGainScale);
switch(sendDataToOutputBuffer(data->cb, NULL, data->dc, 1, data->chunk,
data->chunk_length, data->time, data->bitRate))
data->chunk_length, data->time, data->bitRate,
data->replayGainInfo))
{
case OUTPUT_BUFFER_DC_STOP:
return -1;
......
......@@ -191,7 +191,7 @@ int mod_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
time += ret*secPerByte;
sendDataToOutputBuffer(cb, NULL, dc, 0,
(char *)data->audio_buffer, ret, time,
0);
0, NULL);
}
flushOutputBuffer(cb);
......
......@@ -585,7 +585,8 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
data->outputPtr-
data->outputBuffer,
data->elapsedTime,
data->bitRate/1000);
data->bitRate/1000,
NULL);
if(ret == OUTPUT_BUFFER_DC_STOP) {
data->flush = 0;
return DECODE_BREAK;
......@@ -710,7 +711,8 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
data.inStream->seekable,
data.outputBuffer,
data.outputPtr-data.outputBuffer,
data.elapsedTime,data.bitRate/1000);
data.elapsedTime,data.bitRate/1000,
NULL);
}
closeInputStream(inStream);
......
......@@ -284,7 +284,7 @@ int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
sampleBuffer+=offset*channels*2;
sendDataToOutputBuffer(cb, NULL, dc, 1, sampleBuffer,
sampleBufferLen, time, bitRate);
sampleBufferLen, time, bitRate, NULL);
if(dc->stop) {
eof = 1;
break;
......
......@@ -114,62 +114,45 @@ char * ogg_parseComment(char * comment, char * needle) {
return NULL;
}
float ogg_getReplayGainScale(char ** comments) {
int trackGainFound = 0;
int albumGainFound = 0;
float trackGain = 1.0;
float albumGain = 1.0;
float trackPeak = 0.0;
float albumPeak = 0.0;
void ogg_getReplayGainInfo(char ** comments, ReplayGainInfo ** infoPtr) {
char * temp;
int replayGainState = getReplayGainState();
int found = 0;
if(replayGainState == REPLAYGAIN_OFF) return 1.0;
if(*infoPtr) freeReplayGainInfo(*infoPtr);
*infoPtr = newReplayGainInfo();
while(*comments) {
if((temp = ogg_parseComment(*comments,"replaygain_track_gain")))
{
trackGain = atof(temp);
trackGainFound = 1;
(*infoPtr)->trackGain = atof(temp);
found = 1;
}
else if((temp = ogg_parseComment(*comments,
"replaygain_album_gain")))
{
albumGain = atof(temp);
albumGainFound = 1;
(*infoPtr)->albumGain = atof(temp);
found = 1;
}
else if((temp = ogg_parseComment(*comments,
"replaygain_track_peak")))
{
trackPeak = atof(temp);
(*infoPtr)->trackPeak = atof(temp);
found = 1;
}
else if((temp = ogg_parseComment(*comments,
"replaygain_album_peak")))
{
albumPeak = atof(temp);
(*infoPtr)->albumPeak = atof(temp);
found = 1;
}
comments++;
}
switch(replayGainState) {
case REPLAYGAIN_ALBUM:
if(albumGainFound) {
return computeReplayGainScale(albumGain,albumPeak);
}
else if(trackGainFound) {
return computeReplayGainScale(trackGain,trackPeak);
}
case REPLAYGAIN_TRACK:
if(trackGainFound) {
return computeReplayGainScale(trackGain,trackPeak);
}
else if(albumGainFound) {
return computeReplayGainScale(albumGain,albumPeak);
}
}
return 1.0;
if(!found) {
freeReplayGainInfo(*infoPtr);
*infoPtr = NULL;
}
}
MpdTag * oggCommentsParse(char ** comments) {
......@@ -248,7 +231,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
int chunkpos = 0;
long bitRate = 0;
long test;
float replayGainScale = 1.0;
ReplayGainInfo * replayGainInfo = NULL;
char ** comments;
data.inStream = inStream;
......@@ -259,10 +242,30 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
callbacks.close_func = ogg_close_cb;
callbacks.tell_func = ogg_tell_cb;
if(ov_open_callbacks(&data, &vf, NULL, 0, callbacks) < 0) {
if((ret = ov_open_callbacks(&data, &vf, NULL, 0, callbacks)) < 0) {
closeInputStream(inStream);
if(!dc->stop) {
ERROR("Input does not appear to be an Ogg Vorbis stream.\n");
ERROR("Error decoding Ogg Vorbis stream: ");
switch(ret) {
case OV_EREAD:
ERROR("read error\n");
break;
case OV_ENOTVORBIS:
ERROR("not vorbis stream\n");
break;
case OV_EVERSION:
ERROR("vorbis version mismatch\n");
break;
case OV_EBADHEADER:
ERROR("invalid vorbis header\n");
break;
case OV_EFAULT:
ERROR("internal logic error\n");
break;
default:
ERROR("unknown error\n");
break;
}
return -1;
}
else {
......@@ -304,7 +307,7 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
comments = ov_comment(&vf, -1)->user_comments;
putOggCommentsIntoOutputBuffer(cb, inStream->metaName,
comments);
replayGainScale = ogg_getReplayGainScale(comments);
ogg_getReplayGainInfo(comments, &replayGainInfo);
}
prev_section = current_section;
......@@ -321,14 +324,13 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
if((test = ov_bitrate_instant(&vf))>0) {
bitRate = test/1000;
}
doReplayGain(chunk,chunkpos,&(dc->audioFormat),
replayGainScale);
sendDataToOutputBuffer(cb, inStream, dc,
inStream->seekable,
chunk, chunkpos,
ov_pcm_tell(&vf)/
dc->audioFormat.sampleRate,
bitRate);
bitRate,
replayGainInfo);
chunkpos = 0;
if(dc->stop) break;
}
......@@ -337,9 +339,11 @@ int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
if(!dc->stop && chunkpos > 0) {
sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
chunk, chunkpos,
ov_time_tell(&vf), bitRate);
ov_time_tell(&vf), bitRate, replayGainInfo);
}
if(replayGainInfo) freeReplayGainInfo(replayGainInfo);
ov_clear(&vf);
flushOutputBuffer(cb);
......
......@@ -68,4 +68,3 @@ size_t readFromInputStream(InputStream * inStream, void * ptr, size_t size,
size_t nmemb);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -37,4 +37,3 @@ int inputStream_fileAtEOF(InputStream * inStream);
int inputStream_fileBuffer(InputStream * inStream);
#endif
/* vim:set shiftwidth=8 tabstop=8 expandtab: */
......@@ -42,8 +42,8 @@
#define HTTP_CONN_STATE_OPEN 3
#define HTTP_CONN_STATE_REOPEN 4
#define HTTP_BUFFER_SIZE 131072
#define HTTP_PREBUFFER_SIZE (HTTP_BUFFER_SIZE >> 2)
#define HTTP_BUFFER_SIZE_DEFAULT 131072
#define HTTP_PREBUFFER_SIZE_DEFAULT (HTTP_BUFFER_SIZE_DEFAULT >> 2)
#define HTTP_REDIRECT_MAX 10
......@@ -51,6 +51,8 @@ static char * proxyHost = NULL;
static int proxyPort = 0;
static char * proxyUser = NULL;
static char * proxyPassword = NULL;
static int bufferSize = HTTP_BUFFER_SIZE_DEFAULT;
static int prebufferSize = HTTP_PREBUFFER_SIZE_DEFAULT;
typedef struct _InputStreemHTTPData {
char * host;
......@@ -58,7 +60,7 @@ typedef struct _InputStreemHTTPData {
int port;
int sock;
int connState;
char buffer[HTTP_BUFFER_SIZE];
char * buffer;
size_t buflen;
int timesRedirected;
int icyMetaint;
......@@ -133,6 +135,42 @@ void inputStream_initHttp() {
param->line);
exit(EXIT_FAILURE);
}
param = getConfigParam(CONF_HTTP_BUFFER_SIZE);
if(param) {
bufferSize = strtol(param->value, &test, 10);
if(bufferSize <= 0 || *test != '\0') {
ERROR("\"%s\" specified for %s at line %i is not a "
"positivie intenger\n",
param->value, CONF_HTTP_BUFFER_SIZE,
param->line);
exit(EXIT_FAILURE);
}
bufferSize *= 1024;
if(prebufferSize > bufferSize) prebufferSize = bufferSize;
}
param = getConfigParam(CONF_HTTP_PREBUFFER_SIZE);
if(param) {
prebufferSize = strtol(param->value, &test, 10);
if(bufferSize <= 0 || *test != '\0') {
ERROR("\"%s\" specified for %s at line %i is not a "
"positivie intenger\n",
param->value, CONF_HTTP_PREBUFFER_SIZE,
param->line);
exit(EXIT_FAILURE);
}
prebufferSize *= 1024;
if(prebufferSize > bufferSize) bufferSize = prebufferSize;
}
}
/* base64 code taken from xmms */
......@@ -223,6 +261,7 @@ static InputStreamHTTPData * newInputStreamHTTPData() {
ret->icyMetaint = 0;
ret->prebuffer = 0;
ret->icyOffset = 0;
ret->buffer = malloc(bufferSize);
return ret;
}
......@@ -233,6 +272,8 @@ static void freeInputStreamHTTPData(InputStreamHTTPData * data) {
if(data->proxyAuth) free(data->proxyAuth);
if(data->httpAuth) free(data->httpAuth);
free(data->buffer);
free(data);
}
......@@ -489,14 +530,14 @@ static int getHTTPHello(InputStream * inStream) {
return -1;
}
if(data->buflen >= HTTP_BUFFER_SIZE-1) {
if(data->buflen >= bufferSize-1) {
data->connState = HTTP_CONN_STATE_CLOSED;
close(data->sock);
return -1;
}
readed = recv(data->sock, data->buffer+data->buflen,
HTTP_BUFFER_SIZE-1-data->buflen, 0);
bufferSize-1-data->buflen, 0);
if(readed < 0 && (errno == EAGAIN || errno == EINTR)) return 0;
......@@ -720,7 +761,7 @@ size_t inputStream_httpRead(InputStream * inStream, void * ptr, size_t size,
if(metalen < 0) metalen = 0;
if(metalen+1 > data->buflen) {
/* damn that's some fucking big metadata! */
if(HTTP_BUFFER_SIZE < metalen+1) {
if(bufferSize < metalen+1) {
data->connState =
HTTP_CONN_STATE_CLOSED;
close(data->sock);
......@@ -810,13 +851,13 @@ int inputStream_httpBuffer(InputStream * inStream) {
if(data->buflen == 0 || data->buflen < data->icyMetaint) {
data->prebuffer = 1;
}
else if(data->buflen > HTTP_PREBUFFER_SIZE) data->prebuffer = 0;
else if(data->buflen > prebufferSize) data->prebuffer = 0;
if(data->connState == HTTP_CONN_STATE_OPEN &&
data->buflen < HTTP_BUFFER_SIZE-1)
data->buflen < bufferSize-1)
{
readed = read(data->sock, data->buffer+data->buflen,
(size_t)(HTTP_BUFFER_SIZE-1-data->buflen));
(size_t)(bufferSize-1-data->buflen));
if(readed < 0 && (errno == EAGAIN || errno == EINTR)) {
readed = 0;
......@@ -830,7 +871,7 @@ int inputStream_httpBuffer(InputStream * inStream) {
data->buflen += readed;
}
if(data->buflen > HTTP_PREBUFFER_SIZE) data->prebuffer = 0;
if(data->buflen > prebufferSize) data->prebuffer = 0;
return (readed ? 1 : 0);
}
......@@ -37,4 +37,3 @@ int inputStream_httpAtEOF(InputStream * inStream);
int inputStream_httpBuffer(InputStream * inStream);
#endif
/* vim:set shiftwidth=8 tabstop=8 expandtab: */
......@@ -337,8 +337,7 @@ void addInterfacesReadyToReadAndListenSocketToFdSet(fd_set * fds, int * fdmax) {
int i;
FD_ZERO(fds);
FD_SET(listenSocket,fds);
if(*fdmax<listenSocket) *fdmax = listenSocket;
addListenSocketsToFdSet(fds, fdmax);
for(i=0;i<interface_max_connections;i++) {
if(interfaces[i].open && !interfaces[i].expired && !interfaces[i].bufferList) {
......@@ -396,7 +395,7 @@ int doIOForInterfaces() {
addInterfacesForBufferFlushToFdSet(&wfds,&fdmax);
while((selret = select(fdmax+1,&rfds,&wfds,NULL,&tv))) {
if(FD_ISSET(listenSocket,&rfds)) getConnections(listenSocket);
getConnections(&rfds);
if(selret<0 && errno==EINTR) break;
else if(selret<0) {
closeNextErroredInterface();
......
......@@ -482,4 +482,3 @@ void sortList(List * list) {
quickSort(list->nodesArray,0,list->numberOfNodes-1);
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -103,4 +103,3 @@ void clearList(List * list);
void sortList(List * list);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -41,10 +41,10 @@
#define ALLOW_REUSE 1
int listenSocket;
int * listenSockets = NULL;
int numberOfListenSockets = 0;
int establish(unsigned short port) {
ConfigParam * param;
static int establishListen(unsigned int port, ConfigParam * param) {
int allowReuse = ALLOW_REUSE;
int sock;
struct sockaddr * addrp;
......@@ -62,9 +62,8 @@ int establish(unsigned short port) {
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
param = getConfigParam(CONF_BIND_TO_ADDRESS);
if(!param || 0==strcmp(param->value, "any")==0) {
if(!param || 0==strcmp(param->value, "any")) {
DEBUG("binding to any address\n");
#ifdef HAVE_IPV6
if(ipv6Supported()) {
sin6.sin6_addr = in6addr_any;
......@@ -81,6 +80,7 @@ int establish(unsigned short port) {
}
else {
struct hostent * he;
DEBUG("binding to address for %s\n", param->value);
if(!(he = gethostbyname(param->value))) {
ERROR("can't lookup host \"%s\" at line %i\n",
param->value, param->line);
......@@ -129,54 +129,104 @@ int establish(unsigned short port) {
break;
default:
ERROR("unknown address family: %i\n",addrp->sa_family);
return -1;
exit(EXIT_FAILURE);
}
if((sock = socket(pf,SOCK_STREAM,0)) < 0) {
ERROR("socket < 0\n");
return -1;
exit(EXIT_FAILURE);
}
if(fcntl(sock, F_SETFL ,fcntl(sock, F_GETFL) | O_NONBLOCK) < 0) {
ERROR("problems setting nonblocking on listen socket: %s\n",
strerror(errno));
exit(EXIT_FAILURE);
}
if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&allowReuse,
sizeof(allowReuse))<0)
{
close(sock);
ERROR("problems setsockopt'ing\n");
return -1;
exit(EXIT_FAILURE);
}
if(bind(sock,addrp,addrlen)<0) {
ERROR("unable to bind port %i, maybe MPD is still running?\n",
port);
close(sock);
return -1;
ERROR("unable to bind port %u", port);
if(param) ERROR(" (for address at line %i)", param->line);
ERROR(": %s\n", strerror(errno));
ERROR("maybe MPD is still running?\n");
exit(EXIT_FAILURE);
}
if(listen(sock,5)<0) {
close(sock);
ERROR("problems listen'ing\n");
return -1;
ERROR("problems listen'ing: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
return sock;
}
void getConnections(int sock) {
fd_set fdsr;
void establish(unsigned int port) {
ConfigParam * param = getNextConfigParam(CONF_BIND_TO_ADDRESS, NULL);
do {
numberOfListenSockets++;
listenSockets = realloc(listenSockets,
sizeof(int)*numberOfListenSockets);
listenSockets[numberOfListenSockets-1] =
establishListen(port, param);
} while ((param = getNextConfigParam(CONF_BIND_TO_ADDRESS, param)));
}
void addListenSocketsToFdSet(fd_set * fds, int * fdmax) {
int i;
for(i=0; i<numberOfListenSockets; i++) {
FD_SET(listenSockets[i], fds);
if(listenSockets[i] > *fdmax) *fdmax = listenSockets[i];
}
}
void closeAllListenSockets() {
int i;
DEBUG("closeAllListenSockets called\n");
for(i=0; i<numberOfListenSockets; i++) {
DEBUG("closing listen scoket %i\n", i);
while(close(listenSockets[i]) < 0 && errno==EINTR);
}
numberOfListenSockets = 0;
free(listenSockets);
listenSockets = NULL;
}
int isAListenSocket(int socket) {
int i;
for(i=0; listenSockets[i] != socket && i<numberOfListenSockets; i++);
return (i < numberOfListenSockets);
}
void getConnections(fd_set * fds) {
int i;
int fd = 0;
struct timeval tv;
struct sockaddr sockAddr;
socklen_t socklen = sizeof(sockAddr);
tv.tv_sec = tv.tv_usec = 0;
fflush(NULL);
FD_ZERO(&fdsr);
FD_SET(sock,&fdsr);
if(select(sock+1,&fdsr,NULL,NULL,&tv)==1 &&
((fd = accept(sock,&sockAddr,&socklen)) >= 0)) {
openAInterface(fd,&sockAddr);
for(i=0; i<numberOfListenSockets; i++) {
if(FD_ISSET(listenSockets[i], fds)) {
if((fd = accept(listenSockets[i], &sockAddr, &socklen))
>= 0)
{
openAInterface(fd,&sockAddr);
}
else if(fd<0 && (errno!=EAGAIN && errno!=EINTR)) {
ERROR("Problems accept()'ing\n");
}
}
}
else if(fd<0) ERROR("Problems accept()'ing\n");
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -21,11 +21,20 @@
#include "../config.h"
extern int listenSocket;
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int establish(unsigned short port);
void establish(unsigned int port);
void getConnections(int sock);
void getConnections(fd_set * fds);
int isAListenSocket(int sock);
void closeAllListenSockets();
/* fdmax should be initialized to something */
void addListenSocketsToFdSet(fd_set * fds, int * fdmax);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -226,12 +226,7 @@ void establishListen(Options * options) {
exit(EXIT_FAILURE);
}
if(options->createDB <= 0 && !options->updateDB &&
(listenSocket = establish(port))<0)
{
ERROR("error binding port\n");
exit(EXIT_FAILURE);
}
if(options->createDB <= 0 && !options->updateDB) establish(port);
}
void changeToUser(Options * options) {
......@@ -427,9 +422,9 @@ int main(int argc, char * argv[]) {
openDB(&options, argv[0]);
initCommands();
initPlayerData();
initAudioConfig();
initAudioDriver();
initPlayerData();
initVolume();
initInterfaces();
initInputStream();
......@@ -453,7 +448,7 @@ int main(int argc, char * argv[]) {
playerKill();
freeAllInterfaces();
close(listenSocket);
closeAllListenSockets();
closeMp3Directory();
closeTables();
finishPlaylist();
......
......@@ -41,4 +41,3 @@ typedef signed long mpd_sint32;
#endif
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -123,4 +123,3 @@ int myfprintfCloseAndOpenLogFile() {
return 0;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -64,7 +64,8 @@ void flushOutputBuffer(OutputBuffer * cb) {
int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
DecoderControl * dc, int seekable, char * dataIn,
long dataInLen, float time, mpd_uint16 bitRate)
long dataInLen, float time, mpd_uint16 bitRate,
ReplayGainInfo * replayGainInfo)
{
mpd_uint16 dataToSend;
mpd_uint16 chunkLeft;
......@@ -91,6 +92,8 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
&(cb->audioFormat),data);
}
doReplayGain(replayGainInfo, data, datalen, &cb->audioFormat);
while(datalen) {
if(currentChunk != cb->end) {
int next = cb->end+1;
......
......@@ -24,6 +24,7 @@
#include "audio.h"
#include "inputStream.h"
#include "metadataChunk.h"
#include "replayGain.h"
#define OUTPUT_BUFFER_DC_STOP -1
#define OUTPUT_BUFFER_DC_SEEK -2
......@@ -50,9 +51,16 @@ void flushOutputBuffer(OutputBuffer * cb);
/* we send inStream for buffering the inputStream while waiting to
send the next chunk */
int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
DecoderControl * dc, int seekable, char * data, long datalen,
float time, mpd_uint16 bitRate);
int sendDataToOutputBuffer(
OutputBuffer * cb,
InputStream * inStream,
DecoderControl * dc,
int seekable,
char * data,
long datalen,
float time,
mpd_uint16 bitRate,
ReplayGainInfo * replayGainInfo);
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag);
......
......@@ -54,4 +54,3 @@ char * sanitizePathDup(char * path);
char * prependCwdToPathDup(char * path);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -39,4 +39,3 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
size_t inSize, AudioFormat * outFormat);
#endif
/* vim:set shiftwidth=8 tabstop=8 expandtab: */
......@@ -136,4 +136,3 @@ void finishPermissions() {
unsigned int getDefaultPermissions() {
return permission_default;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -35,4 +35,3 @@ void finishPermissions();
unsigned int getDefaultPermissions();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -105,22 +105,14 @@ int playerInit() {
player_pid = fork();
if(player_pid==0) {
PlayerControl * pc = &(getPlayerData()->playerControl);
struct sigaction sa;
clearUpdatePid();
unblockSignals();
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
setSigHandlersForDecoder();
finishSigHandlers();
sa.sa_handler = decodeSigHandler;
while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
while(sigaction(SIGTERM,&sa,NULL)<0 && errno==EINTR);
while(sigaction(SIGINT,&sa,NULL)<0 && errno==EINTR);
while(close(listenSocket)<0 && errno==EINTR);
closeAllListenSockets();
freeAllInterfaces();
closeMp3Directory();
finishPlaylist();
......
......@@ -37,6 +37,7 @@ typedef struct _PlayerData {
OutputBuffer buffer;
PlayerControl playerControl;
DecoderControl decoderControl;
mpd_sint8 audioDeviceEnabled[AUDIO_MAX_DEVICES];
} PlayerData;
void initPlayerData();
......@@ -46,4 +47,3 @@ PlayerData * getPlayerData();
void freePlayerData();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -258,7 +258,8 @@ void savePlaylistState() {
while(!(fp = fopen(playlist_stateFile,"w")) && errno==EINTR);
if(!fp) {
ERROR("problems opening state file \"%s\" for "
"writing\n",playlist_stateFile);
"writing: %s\n", playlist_stateFile,
strerror(errno));
return;
}
......@@ -314,7 +315,7 @@ void loadPlaylistFromStateFile(FILE * fp, char * buffer, int state, int current,
playlist_stateFile);
exit(EXIT_FAILURE);
}
if(addToPlaylist(stderr,temp)==0 && current==song) {
if(addToPlaylist(stderr, temp, 0)==0 && current==song) {
if(state!=PLAYER_STATE_STOP) {
playPlaylist(stderr,playlist.length-1,0);
}
......@@ -353,7 +354,8 @@ void readPlaylistState() {
fp = fopen(playlist_stateFile,"r");
if(!fp) {
ERROR("problems opening state file \"%s\" for "
"reading\n",playlist_stateFile);
"reading: %s\n", playlist_stateFile,
strerror(errno));
exit(EXIT_FAILURE);
}
......@@ -593,7 +595,7 @@ void clearPlayerQueue() {
}
}
int addToPlaylist(FILE * fp, char * url) {
int addToPlaylist(FILE * fp, char * url, int printId) {
Song * song;
DEBUG("add to playlist: %s\n",url);
......@@ -611,10 +613,12 @@ int addToPlaylist(FILE * fp, char * url) {
return -1;
}
return addSongToPlaylist(fp,song);
return addSongToPlaylist(fp,song, printId);
}
int addSongToPlaylist(FILE * fp, Song * song) {
int addSongToPlaylist(FILE * fp, Song * song, int printId) {
int id;
if(playlist.length==playlist_max_length) {
commandError(fp, ACK_ERROR_PLAYLIST_MAX,
"playlist is at the max size", NULL);
......@@ -629,10 +633,12 @@ int addSongToPlaylist(FILE * fp, Song * song) {
}
}
id = getNextId();
playlist.songs[playlist.length] = song;
playlist.songMod[playlist.length] = playlist.version;
playlist.order[playlist.length] = playlist.length;
playlist.positionToId[playlist.length] = getNextId();
playlist.positionToId[playlist.length] = id;
playlist.idToPosition[playlist.positionToId[playlist.length]] = playlist.length;
playlist.length++;
......@@ -651,6 +657,8 @@ int addSongToPlaylist(FILE * fp, Song * song) {
incrPlaylistVersion();
if(printId) myfprintf(fp, "Id: %i\n", id);
return 0;
}
......@@ -1398,7 +1406,7 @@ int loadPlaylist(FILE * fp, char * utf8file) {
free(temp);
continue;
}
if((addToPlaylist(stderr,temp))<0) {
if((addToPlaylist(stderr, temp, 0))<0) {
if(!erroredFile) erroredFile = strdup(temp);
}
free(temp);
......
......@@ -42,9 +42,9 @@ void savePlaylistState();
int clearPlaylist(FILE * fp);
int addToPlaylist(FILE * fp, char * file);
int addToPlaylist(FILE * fp, char * file, int printId);
int addSongToPlaylist(FILE * fp, Song * song);
int addSongToPlaylist(FILE * fp, Song * song, int printId);
int showPlaylist(FILE * fp);
......@@ -115,4 +115,3 @@ void playlistVersionChange();
int playlistChanges(FILE * fp, mpd_uint32 version);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -71,11 +71,7 @@ void initReplayGainState() {
}
}
int getReplayGainState() {
return replayGainState;
}
float computeReplayGainScale(float gain, float peak) {
static float computeReplayGainScale(float gain, float peak) {
float scale;
if(gain == 0.0) return(1);
......@@ -89,14 +85,55 @@ float computeReplayGainScale(float gain, float peak) {
return(scale);
}
void doReplayGain(char * buffer, int bufferSize, AudioFormat * format,
float scale)
ReplayGainInfo * newReplayGainInfo() {
ReplayGainInfo * ret = malloc(sizeof(ReplayGainInfo));
ret->albumGain = 0.0;
ret->albumPeak = 1.0;
ret->trackGain = 0.0;
ret->trackPeak = 1.0;
/* set to -1 so that we know in doReplayGain to compute the scale */
ret->scale = -1.0;
return ret;
}
void freeReplayGainInfo(ReplayGainInfo * info) {
free(info);
}
void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize,
AudioFormat * format)
{
mpd_sint16 * buffer16 = (mpd_sint16 *)buffer;
mpd_sint8 * buffer8 = (mpd_sint8 *)buffer;
mpd_sint16 * buffer16;
mpd_sint8 * buffer8;
mpd_sint32 temp32;
float scale;
if(replayGainState == REPLAYGAIN_OFF || !info) return;
if(info->scale < 0) {
switch(replayGainState) {
case REPLAYGAIN_TRACK:
info->scale = computeReplayGainScale(info->trackGain,
info->trackPeak);
break;
default:
info->scale = computeReplayGainScale(info->albumGain,
info->albumPeak);
break;
}
}
if(info->scale <= 1.01 && info->scale >= 0.99) return;
buffer16 = (mpd_sint16 *)buffer;
buffer8 = (mpd_sint8 *)buffer;
scale = info->scale;
if(scale == 1.0) return;
switch(format->bits) {
case 16:
while(bufferSize > 0){
......@@ -122,4 +159,3 @@ void doReplayGain(char * buffer, int bufferSize, AudioFormat * format,
ERROR("%i bits not supported by doReplaygain!\n", format->bits);
}
}
/* End of added code */
......@@ -26,13 +26,23 @@
#define REPLAYGAIN_TRACK 1
#define REPLAYGAIN_ALBUM 2
void initReplayGainState();
typedef struct _ReplayGainInfo {
float albumGain;
float albumPeak;
float trackGain;
float trackPeak;
/* used internally by mpd, to mess with it*/
float scale;
} ReplayGainInfo;
int getReplayGainState();
ReplayGainInfo * newReplayGainInfo();
float computeReplayGainScale(float gain, float peak);
void freeReplayGainInfo(ReplayGainInfo * info);
void initReplayGainState();
void doReplayGain(char * buffer, int bufferSize, AudioFormat * format,
float scale);
void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize,
AudioFormat * format);
#endif
......@@ -25,6 +25,7 @@
#include "signal_check.h"
#include "log.h"
#include "player.h"
#include "decode.h"
#include <signal.h>
#include <sys/types.h>
......@@ -89,6 +90,21 @@ void finishSigHandlers() {
signal_unhandle(SIGHUP);
}
void setSigHandlersForDecoder() {
struct sigaction sa;
finishSigHandlers();
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
while(sigaction(SIGHUP,&sa,NULL)<0 && errno==EINTR);
sa.sa_handler = decodeSigHandler;
while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
while(sigaction(SIGTERM,&sa,NULL)<0 && errno==EINTR);
while(sigaction(SIGINT,&sa,NULL)<0 && errno==EINTR);
}
void ignoreSignals() {
struct sigaction sa;
......@@ -126,4 +142,3 @@ void unblockSignals() {
sigaddset(&sset,SIGTERM);
while(sigprocmask(SIG_UNBLOCK,&sset,NULL)<0 && errno==EINTR);
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -27,6 +27,8 @@ void initSigHandlers();
void finishSigHandlers();
void setSigHandlersForDecoder();
void ignoreSignals();
void blockSignals();
......@@ -38,4 +40,3 @@ void blockTermSignal();
void unblockTermSignal();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -56,5 +56,3 @@ void signal_clear(int sig)
{
__caught_signals[sig] = 0;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -28,5 +28,3 @@ int signal_is_pending(int sig);
void signal_clear(int sig);
#endif /* SIGNAL_CHECK_H */
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -299,4 +299,3 @@ Song * songDup(Song * song) {
return ret;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -72,4 +72,3 @@ int updateSongInfo(Song * song);
Song * songDup(Song * song);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -38,4 +38,3 @@ void initStats();
int printStats(FILE * fp);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -41,4 +41,3 @@ unsigned long numberOfAlbums();
int printAllKeysOfTable(FILE * fp, char * table, char * arg1);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -128,4 +128,3 @@ unsigned char * utf8StrToLatin1Dup(unsigned char * utf8) {
return realloc(ret,len+1);
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -38,4 +38,3 @@ int getVolumeLevel();
int changeVolumeLevel(FILE * fp, int change, int rel);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
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