Add mpd-indent.sh
Indent the entire tree, hopefully we can keep it indented. git-svn-id: https://svn.musicpd.org/mpd/trunk@4410 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
099f0e103f
commit
29a25b9933
260
src/audio.c
260
src/audio.c
@ -41,23 +41,25 @@
|
|||||||
|
|
||||||
static AudioFormat audio_format;
|
static AudioFormat audio_format;
|
||||||
|
|
||||||
static AudioFormat * audio_configFormat = NULL;
|
static AudioFormat *audio_configFormat = NULL;
|
||||||
|
|
||||||
static AudioOutput ** audioOutputArray = NULL;
|
static AudioOutput **audioOutputArray = NULL;
|
||||||
static mpd_uint8 audioOutputArraySize = 0;
|
static mpd_uint8 audioOutputArraySize = 0;
|
||||||
/* the audioEnabledArray should be stuck into shared memory, and then disable
|
/* the audioEnabledArray should be stuck into shared memory, and then disable
|
||||||
and enable in playAudio() routine */
|
and enable in playAudio() routine */
|
||||||
static mpd_sint8 * pdAudioDevicesEnabled = NULL;
|
static mpd_sint8 *pdAudioDevicesEnabled = NULL;
|
||||||
static mpd_sint8 myAudioDevicesEnabled[AUDIO_MAX_DEVICES];
|
static mpd_sint8 myAudioDevicesEnabled[AUDIO_MAX_DEVICES];
|
||||||
|
|
||||||
static mpd_uint8 audioOpened = 0;
|
static mpd_uint8 audioOpened = 0;
|
||||||
|
|
||||||
static mpd_sint32 audioBufferSize = 0;
|
static mpd_sint32 audioBufferSize = 0;
|
||||||
static char * audioBuffer = NULL;
|
static char *audioBuffer = NULL;
|
||||||
static mpd_sint32 audioBufferPos = 0;
|
static mpd_sint32 audioBufferPos = 0;
|
||||||
|
|
||||||
void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
|
void copyAudioFormat(AudioFormat * dest, AudioFormat * src)
|
||||||
if(!src) return;
|
{
|
||||||
|
if (!src)
|
||||||
|
return;
|
||||||
|
|
||||||
memcpy(dest, src, sizeof(AudioFormat));
|
memcpy(dest, src, sizeof(AudioFormat));
|
||||||
}
|
}
|
||||||
@ -65,8 +67,7 @@ void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
|
|||||||
int cmpAudioFormat(AudioFormat * f1, AudioFormat * f2)
|
int cmpAudioFormat(AudioFormat * f1, AudioFormat * f2)
|
||||||
{
|
{
|
||||||
if (f1 && f2 && (f1->sampleRate == f2->sampleRate) &&
|
if (f1 && f2 && (f1->sampleRate == f2->sampleRate) &&
|
||||||
(f1->bits == f2->bits) &&
|
(f1->bits == f2->bits) && (f1->channels == f2->channels))
|
||||||
(f1->channels == f2->channels))
|
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -79,8 +80,8 @@ extern AudioOutputPlugin pulsePlugin;
|
|||||||
extern AudioOutputPlugin mvpPlugin;
|
extern AudioOutputPlugin mvpPlugin;
|
||||||
extern AudioOutputPlugin shoutPlugin;
|
extern AudioOutputPlugin shoutPlugin;
|
||||||
|
|
||||||
|
void loadAudioDrivers(void)
|
||||||
void loadAudioDrivers(void) {
|
{
|
||||||
initAudioOutputPlugins();
|
initAudioOutputPlugins();
|
||||||
loadAudioOutputPlugin(&alsaPlugin);
|
loadAudioOutputPlugin(&alsaPlugin);
|
||||||
loadAudioOutputPlugin(&aoPlugin);
|
loadAudioOutputPlugin(&aoPlugin);
|
||||||
@ -92,15 +93,16 @@ void loadAudioDrivers(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* make sure initPlayerData is called before this function!! */
|
/* make sure initPlayerData is called before this function!! */
|
||||||
void initAudioDriver(void) {
|
void initAudioDriver(void)
|
||||||
ConfigParam * param = NULL;
|
{
|
||||||
|
ConfigParam *param = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
loadAudioDrivers();
|
loadAudioDrivers();
|
||||||
|
|
||||||
pdAudioDevicesEnabled = (getPlayerData())->audioDeviceEnabled;
|
pdAudioDevicesEnabled = (getPlayerData())->audioDeviceEnabled;
|
||||||
|
|
||||||
for(i = 0; i < AUDIO_MAX_DEVICES; i++) {
|
for (i = 0; i < AUDIO_MAX_DEVICES; i++) {
|
||||||
pdAudioDevicesEnabled[i] = 1;
|
pdAudioDevicesEnabled[i] = 1;
|
||||||
myAudioDevicesEnabled[i] = 1;
|
myAudioDevicesEnabled[i] = 1;
|
||||||
}
|
}
|
||||||
@ -111,7 +113,7 @@ void initAudioDriver(void) {
|
|||||||
AudioOutput *output;
|
AudioOutput *output;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
if(audioOutputArraySize == AUDIO_MAX_DEVICES) {
|
if (audioOutputArraySize == AUDIO_MAX_DEVICES) {
|
||||||
ERROR("only up to 255 audio output devices are "
|
ERROR("only up to 255 audio output devices are "
|
||||||
"supported");
|
"supported");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -120,10 +122,11 @@ void initAudioDriver(void) {
|
|||||||
i = audioOutputArraySize++;
|
i = audioOutputArraySize++;
|
||||||
|
|
||||||
audioOutputArray = realloc(audioOutputArray,
|
audioOutputArray = realloc(audioOutputArray,
|
||||||
audioOutputArraySize*sizeof(AudioOutput *));
|
audioOutputArraySize *
|
||||||
|
sizeof(AudioOutput *));
|
||||||
|
|
||||||
output = newAudioOutput(param);
|
output = newAudioOutput(param);
|
||||||
if(!output && param) {
|
if (!output && param) {
|
||||||
ERROR("problems configuring output device defined at "
|
ERROR("problems configuring output device defined at "
|
||||||
"line %i\n", param->line);
|
"line %i\n", param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -131,50 +134,51 @@ void initAudioDriver(void) {
|
|||||||
|
|
||||||
/* require output names to be unique: */
|
/* require output names to be unique: */
|
||||||
for (j = i - 1; j >= 0; --j) {
|
for (j = i - 1; j >= 0; --j) {
|
||||||
if ( !strcmp( output->name,
|
if (!strcmp(output->name, audioOutputArray[j]->name)) {
|
||||||
audioOutputArray[j]->name) ) {
|
|
||||||
ERROR("output devices with identical "
|
ERROR("output devices with identical "
|
||||||
"names: %s\n",
|
"names: %s\n", output->name);
|
||||||
output->name);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
audioOutputArray[i] = output;
|
audioOutputArray[i] = output;
|
||||||
} while((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param)));
|
} while ((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void getOutputAudioFormat(AudioFormat * inAudioFormat,
|
void getOutputAudioFormat(AudioFormat * inAudioFormat,
|
||||||
AudioFormat * outAudioFormat)
|
AudioFormat * outAudioFormat)
|
||||||
{
|
{
|
||||||
if(audio_configFormat) {
|
if (audio_configFormat) {
|
||||||
copyAudioFormat(outAudioFormat,audio_configFormat);
|
copyAudioFormat(outAudioFormat, audio_configFormat);
|
||||||
}
|
} else
|
||||||
else copyAudioFormat(outAudioFormat,inAudioFormat);
|
copyAudioFormat(outAudioFormat, inAudioFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initAudioConfig(void) {
|
void initAudioConfig(void)
|
||||||
ConfigParam * param = getConfigParam(CONF_AUDIO_OUTPUT_FORMAT);
|
{
|
||||||
|
ConfigParam *param = getConfigParam(CONF_AUDIO_OUTPUT_FORMAT);
|
||||||
|
|
||||||
if(NULL == param || NULL == param->value) return;
|
if (NULL == param || NULL == param->value)
|
||||||
|
return;
|
||||||
|
|
||||||
audio_configFormat = malloc(sizeof(AudioFormat));
|
audio_configFormat = malloc(sizeof(AudioFormat));
|
||||||
|
|
||||||
if(0 != parseAudioConfig(audio_configFormat, param->value)) {
|
if (0 != parseAudioConfig(audio_configFormat, param->value)) {
|
||||||
ERROR("error parsing \"%s\" at line %i\n",
|
ERROR("error parsing \"%s\" at line %i\n",
|
||||||
CONF_AUDIO_OUTPUT_FORMAT, param->line);
|
CONF_AUDIO_OUTPUT_FORMAT, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
|
int parseAudioConfig(AudioFormat * audioFormat, char *conf)
|
||||||
char * test;
|
{
|
||||||
|
char *test;
|
||||||
|
|
||||||
memset(audioFormat,0,sizeof(AudioFormat));
|
memset(audioFormat, 0, sizeof(AudioFormat));
|
||||||
|
|
||||||
audioFormat->sampleRate = strtol(conf,&test,10);
|
audioFormat->sampleRate = strtol(conf, &test, 10);
|
||||||
|
|
||||||
if(*test!=':') {
|
if (*test != ':') {
|
||||||
ERROR("error parsing audio output format: %s\n",conf);
|
ERROR("error parsing audio output format: %s\n", conf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,22 +192,22 @@ int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
|
|||||||
ERROR("sample rate %i can not be used for audio output\n",
|
ERROR("sample rate %i can not be used for audio output\n",
|
||||||
(int)audioFormat->sampleRate);
|
(int)audioFormat->sampleRate);
|
||||||
return -1
|
return -1
|
||||||
}*/
|
} */
|
||||||
|
|
||||||
if(audioFormat->sampleRate <= 0) {
|
if (audioFormat->sampleRate <= 0) {
|
||||||
ERROR("sample rate %i is not >= 0\n",
|
ERROR("sample rate %i is not >= 0\n",
|
||||||
(int)audioFormat->sampleRate);
|
(int)audioFormat->sampleRate);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioFormat->bits = strtol(test+1,&test,10);
|
audioFormat->bits = strtol(test + 1, &test, 10);
|
||||||
|
|
||||||
if(*test!=':') {
|
if (*test != ':') {
|
||||||
ERROR("error parsing audio output format: %s\n",conf);
|
ERROR("error parsing audio output format: %s\n", conf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(audioFormat->bits) {
|
switch (audioFormat->bits) {
|
||||||
case 16:
|
case 16:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -212,14 +216,14 @@ int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioFormat->channels = strtol(test+1,&test,10);
|
audioFormat->channels = strtol(test + 1, &test, 10);
|
||||||
|
|
||||||
if(*test!='\0') {
|
if (*test != '\0') {
|
||||||
ERROR("error parsing audio output format: %s\n",conf);
|
ERROR("error parsing audio output format: %s\n", conf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(audioFormat->channels) {
|
switch (audioFormat->channels) {
|
||||||
case 1:
|
case 1:
|
||||||
case 2:
|
case 2:
|
||||||
break;
|
break;
|
||||||
@ -232,14 +236,17 @@ int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishAudioConfig(void) {
|
void finishAudioConfig(void)
|
||||||
if(audio_configFormat) free(audio_configFormat);
|
{
|
||||||
|
if (audio_configFormat)
|
||||||
|
free(audio_configFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishAudioDriver(void) {
|
void finishAudioDriver(void)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < audioOutputArraySize; i++) {
|
for (i = 0; i < audioOutputArraySize; i++) {
|
||||||
finishAudioOutput(audioOutputArray[i]);
|
finishAudioOutput(audioOutputArray[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,44 +255,49 @@ void finishAudioDriver(void) {
|
|||||||
audioOutputArraySize = 0;
|
audioOutputArraySize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isCurrentAudioFormat(AudioFormat * audioFormat) {
|
int isCurrentAudioFormat(AudioFormat * audioFormat)
|
||||||
if(!audioFormat) return 1;
|
{
|
||||||
|
if (!audioFormat)
|
||||||
|
return 1;
|
||||||
|
|
||||||
if(cmpAudioFormat(audioFormat, &audio_format) != 0) return 0;
|
if (cmpAudioFormat(audioFormat, &audio_format) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syncAudioDevicesEnabledArrays(void) {
|
static void syncAudioDevicesEnabledArrays(void)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memcpy(myAudioDevicesEnabled, pdAudioDevicesEnabled,AUDIO_MAX_DEVICES);
|
memcpy(myAudioDevicesEnabled, pdAudioDevicesEnabled, AUDIO_MAX_DEVICES);
|
||||||
|
|
||||||
for(i = 0; i < audioOutputArraySize; i++) {
|
for (i = 0; i < audioOutputArraySize; i++) {
|
||||||
if(myAudioDevicesEnabled[i]) {
|
if (myAudioDevicesEnabled[i]) {
|
||||||
openAudioOutput(audioOutputArray[i], &audio_format);
|
openAudioOutput(audioOutputArray[i], &audio_format);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dropBufferedAudioOutput(audioOutputArray[i]);
|
dropBufferedAudioOutput(audioOutputArray[i]);
|
||||||
closeAudioOutput(audioOutputArray[i]);
|
closeAudioOutput(audioOutputArray[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flushAudioBuffer(void) {
|
static int flushAudioBuffer(void)
|
||||||
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
if(audioBufferPos == 0) return 0;
|
if (audioBufferPos == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if(0 != memcmp(pdAudioDevicesEnabled, myAudioDevicesEnabled,
|
if (0 != memcmp(pdAudioDevicesEnabled, myAudioDevicesEnabled,
|
||||||
AUDIO_MAX_DEVICES))
|
AUDIO_MAX_DEVICES)) {
|
||||||
{
|
|
||||||
syncAudioDevicesEnabledArrays();
|
syncAudioDevicesEnabledArrays();
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < audioOutputArraySize; i++) {
|
for (i = 0; i < audioOutputArraySize; i++) {
|
||||||
if(!myAudioDevicesEnabled[i]) continue;
|
if (!myAudioDevicesEnabled[i])
|
||||||
|
continue;
|
||||||
err = playAudioOutput(audioOutputArray[i], audioBuffer,
|
err = playAudioOutput(audioOutputArray[i], audioBuffer,
|
||||||
audioBufferPos);
|
audioBufferPos);
|
||||||
if (!err)
|
if (!err)
|
||||||
@ -301,32 +313,36 @@ static int flushAudioBuffer(void) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int openAudioDevice(AudioFormat * audioFormat) {
|
int openAudioDevice(AudioFormat * audioFormat)
|
||||||
|
{
|
||||||
int isCurrentFormat = isCurrentAudioFormat(audioFormat);
|
int isCurrentFormat = isCurrentAudioFormat(audioFormat);
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(!audioOutputArray) return -1;
|
if (!audioOutputArray)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(!audioOpened || !isCurrentFormat) {
|
if (!audioOpened || !isCurrentFormat) {
|
||||||
flushAudioBuffer();
|
flushAudioBuffer();
|
||||||
copyAudioFormat(&audio_format, audioFormat);
|
copyAudioFormat(&audio_format, audioFormat);
|
||||||
audioBufferSize = (audio_format.bits >> 3)*
|
audioBufferSize = (audio_format.bits >> 3) *
|
||||||
audio_format.channels;
|
audio_format.channels;
|
||||||
audioBufferSize*= audio_format.sampleRate >> 5;
|
audioBufferSize *= audio_format.sampleRate >> 5;
|
||||||
audioBuffer = realloc(audioBuffer, audioBufferSize);
|
audioBuffer = realloc(audioBuffer, audioBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
syncAudioDevicesEnabledArrays();
|
syncAudioDevicesEnabledArrays();
|
||||||
|
|
||||||
for(i = 0; i < audioOutputArraySize; i++) {
|
for (i = 0; i < audioOutputArraySize; i++) {
|
||||||
if(audioOutputArray[i]->open) ret = 0;
|
if (audioOutputArray[i]->open)
|
||||||
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ret == 0) audioOpened = 1;
|
if (ret == 0)
|
||||||
|
audioOpened = 1;
|
||||||
else {
|
else {
|
||||||
/* close all devices if there was an error */
|
/* close all devices if there was an error */
|
||||||
for(i = 0; i < audioOutputArraySize; i++) {
|
for (i = 0; i < audioOutputArraySize; i++) {
|
||||||
closeAudioOutput(audioOutputArray[i]);
|
closeAudioOutput(audioOutputArray[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,48 +352,53 @@ int openAudioDevice(AudioFormat * audioFormat) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int playAudio(char * playChunk, int size) {
|
int playAudio(char *playChunk, int size)
|
||||||
|
{
|
||||||
int send;
|
int send;
|
||||||
|
|
||||||
while(size > 0) {
|
while (size > 0) {
|
||||||
send = audioBufferSize-audioBufferPos;
|
send = audioBufferSize - audioBufferPos;
|
||||||
send = send < size ? send : size;
|
send = send < size ? send : size;
|
||||||
|
|
||||||
memcpy(audioBuffer+audioBufferPos, playChunk, send);
|
memcpy(audioBuffer + audioBufferPos, playChunk, send);
|
||||||
audioBufferPos += send;
|
audioBufferPos += send;
|
||||||
size -= send;
|
size -= send;
|
||||||
playChunk+= send;
|
playChunk += send;
|
||||||
|
|
||||||
if(audioBufferPos == audioBufferSize) {
|
if (audioBufferPos == audioBufferSize) {
|
||||||
if( flushAudioBuffer() < 0 ) return -1;
|
if (flushAudioBuffer() < 0)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isAudioDeviceOpen(void) {
|
int isAudioDeviceOpen(void)
|
||||||
|
{
|
||||||
return audioOpened;
|
return audioOpened;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dropBufferedAudio(void) {
|
void dropBufferedAudio(void)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(0 != memcmp(pdAudioDevicesEnabled, myAudioDevicesEnabled,
|
if (0 != memcmp(pdAudioDevicesEnabled, myAudioDevicesEnabled,
|
||||||
AUDIO_MAX_DEVICES))
|
AUDIO_MAX_DEVICES)) {
|
||||||
{
|
|
||||||
syncAudioDevicesEnabledArrays();
|
syncAudioDevicesEnabledArrays();
|
||||||
}
|
}
|
||||||
|
|
||||||
audioBufferPos = 0;
|
audioBufferPos = 0;
|
||||||
|
|
||||||
for(i = 0; i < audioOutputArraySize; i++) {
|
for (i = 0; i < audioOutputArraySize; i++) {
|
||||||
if(!myAudioDevicesEnabled[i]) continue;
|
if (!myAudioDevicesEnabled[i])
|
||||||
|
continue;
|
||||||
dropBufferedAudioOutput(audioOutputArray[i]);
|
dropBufferedAudioOutput(audioOutputArray[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeAudioDevice(void) {
|
void closeAudioDevice(void)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
flushAudioBuffer();
|
flushAudioBuffer();
|
||||||
@ -386,23 +407,25 @@ void closeAudioDevice(void) {
|
|||||||
audioBuffer = NULL;
|
audioBuffer = NULL;
|
||||||
audioBufferSize = 0;
|
audioBufferSize = 0;
|
||||||
|
|
||||||
for(i = 0; i < audioOutputArraySize; i++) {
|
for (i = 0; i < audioOutputArraySize; i++) {
|
||||||
closeAudioOutput(audioOutputArray[i]);
|
closeAudioOutput(audioOutputArray[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
audioOpened = 0;
|
audioOpened = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendMetadataToAudioDevice(MpdTag * tag) {
|
void sendMetadataToAudioDevice(MpdTag * tag)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < audioOutputArraySize; i++) {
|
for (i = 0; i < audioOutputArraySize; i++) {
|
||||||
sendMetadataToAudioOutput(audioOutputArray[i], tag);
|
sendMetadataToAudioOutput(audioOutputArray[i], tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int enableAudioDevice(FILE * fp, int device) {
|
int enableAudioDevice(FILE * fp, int device)
|
||||||
if(device < 0 || device >= audioOutputArraySize) {
|
{
|
||||||
|
if (device < 0 || device >= audioOutputArraySize) {
|
||||||
commandError(fp, ACK_ERROR_ARG, "audio output device id %i "
|
commandError(fp, ACK_ERROR_ARG, "audio output device id %i "
|
||||||
"doesn't exist\n", device);
|
"doesn't exist\n", device);
|
||||||
return -1;
|
return -1;
|
||||||
@ -413,8 +436,9 @@ int enableAudioDevice(FILE * fp, int device) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int disableAudioDevice(FILE * fp, int device) {
|
int disableAudioDevice(FILE * fp, int device)
|
||||||
if(device < 0 || device >= audioOutputArraySize) {
|
{
|
||||||
|
if (device < 0 || device >= audioOutputArraySize) {
|
||||||
commandError(fp, ACK_ERROR_ARG, "audio output device id %i "
|
commandError(fp, ACK_ERROR_ARG, "audio output device id %i "
|
||||||
"doesn't exist\n", device);
|
"doesn't exist\n", device);
|
||||||
return -1;
|
return -1;
|
||||||
@ -425,10 +449,11 @@ int disableAudioDevice(FILE * fp, int device) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printAudioDevices(FILE * fp) {
|
void printAudioDevices(FILE * fp)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < audioOutputArraySize; i++) {
|
for (i = 0; i < audioOutputArraySize; i++) {
|
||||||
myfprintf(fp, "outputid: %i\n", i);
|
myfprintf(fp, "outputid: %i\n", i);
|
||||||
myfprintf(fp, "outputname: %s\n", audioOutputArray[i]->name);
|
myfprintf(fp, "outputname: %s\n", audioOutputArray[i]->name);
|
||||||
myfprintf(fp, "outputenabled: %i\n",
|
myfprintf(fp, "outputenabled: %i\n",
|
||||||
@ -436,7 +461,8 @@ void printAudioDevices(FILE * fp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveAudioDevicesState(void) {
|
void saveAudioDevicesState(void)
|
||||||
|
{
|
||||||
char *stateFile;
|
char *stateFile;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
int i;
|
int i;
|
||||||
@ -444,8 +470,8 @@ void saveAudioDevicesState(void) {
|
|||||||
if (!(stateFile = getStateFile()))
|
if (!(stateFile = getStateFile()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while(!(fp = fopen(stateFile,"a")) && errno==EINTR);
|
while (!(fp = fopen(stateFile, "a")) && errno == EINTR) ;
|
||||||
if(!fp) {
|
if (!fp) {
|
||||||
ERROR("problems opening state file \"%s\" for "
|
ERROR("problems opening state file \"%s\" for "
|
||||||
"writing: %s\n", stateFile, strerror(errno));
|
"writing: %s\n", stateFile, strerror(errno));
|
||||||
return;
|
return;
|
||||||
@ -457,27 +483,27 @@ void saveAudioDevicesState(void) {
|
|||||||
(int)pdAudioDevicesEnabled[i],
|
(int)pdAudioDevicesEnabled[i],
|
||||||
audioOutputArray[i]->name);
|
audioOutputArray[i]->name);
|
||||||
}
|
}
|
||||||
while(fclose(fp) && errno==EINTR);
|
while (fclose(fp) && errno == EINTR) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_audio_device_state(FILE *fp)
|
static void parse_audio_device_state(FILE * fp)
|
||||||
{
|
{
|
||||||
char buffer[AUDIO_BUFFER_SIZE];
|
char buffer[AUDIO_BUFFER_SIZE];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
assert(audioOutputArraySize != 0);
|
assert(audioOutputArraySize != 0);
|
||||||
|
|
||||||
while (myFgets(buffer,AUDIO_BUFFER_SIZE,fp)) {
|
while (myFgets(buffer, AUDIO_BUFFER_SIZE, fp)) {
|
||||||
char *c, *name;
|
char *c, *name;
|
||||||
|
|
||||||
if (strncmp(buffer,AUDIO_DEVICE_STATE,AUDIO_DEVICE_STATE_LEN))
|
if (strncmp(buffer, AUDIO_DEVICE_STATE, AUDIO_DEVICE_STATE_LEN))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
c = strchr(buffer,':');
|
c = strchr(buffer, ':');
|
||||||
if (!c || !(++c))
|
if (!c || !(++c))
|
||||||
goto errline;
|
goto errline;
|
||||||
|
|
||||||
name = strchr(c,':');
|
name = strchr(c, ':');
|
||||||
if (!name || !(++name))
|
if (!name || !(++name))
|
||||||
goto errline;
|
goto errline;
|
||||||
|
|
||||||
@ -488,37 +514,35 @@ static void parse_audio_device_state(FILE *fp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
errline:
|
errline:
|
||||||
/* nonfatal */
|
/* nonfatal */
|
||||||
ERROR("invalid line in state_file: %s\n", buffer);
|
ERROR("invalid line in state_file: %s\n", buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void readAudioDevicesState(void) {
|
void readAudioDevicesState(void)
|
||||||
|
{
|
||||||
char *stateFile;
|
char *stateFile;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (!(stateFile = getStateFile()))
|
if (!(stateFile = getStateFile()))
|
||||||
return;
|
return;
|
||||||
if(stat(stateFile,&st)<0) {
|
if (stat(stateFile, &st) < 0) {
|
||||||
DEBUG("failed to stat state file\n");
|
DEBUG("failed to stat state file\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!S_ISREG(st.st_mode)) {
|
if (!S_ISREG(st.st_mode)) {
|
||||||
ERROR("state file \"%s\" is not a regular file\n",
|
ERROR("state file \"%s\" is not a regular file\n", stateFile);
|
||||||
stateFile);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fp = fopen(stateFile,"r");
|
fp = fopen(stateFile, "r");
|
||||||
if(!fp) {
|
if (!fp) {
|
||||||
ERROR("problems opening state file \"%s\" for "
|
ERROR("problems opening state file \"%s\" for "
|
||||||
"reading: %s\n", stateFile,
|
"reading: %s\n", stateFile, strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
parse_audio_device_state(fp);
|
parse_audio_device_state(fp);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ int cmpAudioFormat(AudioFormat * dest, AudioFormat * src);
|
|||||||
|
|
||||||
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
|
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
|
||||||
|
|
||||||
int parseAudioConfig(AudioFormat * audioFormat, char * conf);
|
int parseAudioConfig(AudioFormat * audioFormat, char *conf);
|
||||||
|
|
||||||
/* make sure initPlayerData is called before this function!! */
|
/* make sure initPlayerData is called before this function!! */
|
||||||
void initAudioConfig();
|
void initAudioConfig();
|
||||||
@ -55,7 +55,7 @@ void finishAudioDriver();
|
|||||||
|
|
||||||
int openAudioDevice(AudioFormat * audioFormat);
|
int openAudioDevice(AudioFormat * audioFormat);
|
||||||
|
|
||||||
int playAudio(char * playChunk,int size);
|
int playAudio(char *playChunk, int size);
|
||||||
|
|
||||||
void dropBufferedAudio();
|
void dropBufferedAudio();
|
||||||
|
|
||||||
|
@ -28,24 +28,30 @@
|
|||||||
#define AUDIO_OUTPUT_NAME "name"
|
#define AUDIO_OUTPUT_NAME "name"
|
||||||
#define AUDIO_OUTPUT_FORMAT "format"
|
#define AUDIO_OUTPUT_FORMAT "format"
|
||||||
|
|
||||||
static List * audioOutputPluginList;
|
static List *audioOutputPluginList;
|
||||||
|
|
||||||
void loadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin) {
|
void loadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin)
|
||||||
if(!audioOutputPlugin->name) return;
|
{
|
||||||
|
if (!audioOutputPlugin->name)
|
||||||
|
return;
|
||||||
insertInList(audioOutputPluginList, audioOutputPlugin->name,
|
insertInList(audioOutputPluginList, audioOutputPlugin->name,
|
||||||
audioOutputPlugin);
|
audioOutputPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin) {
|
void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin)
|
||||||
if(!audioOutputPlugin->name) return;
|
{
|
||||||
|
if (!audioOutputPlugin->name)
|
||||||
|
return;
|
||||||
deleteFromList(audioOutputPluginList, audioOutputPlugin->name);
|
deleteFromList(audioOutputPluginList, audioOutputPlugin->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initAudioOutputPlugins(void) {
|
void initAudioOutputPlugins(void)
|
||||||
|
{
|
||||||
audioOutputPluginList = makeList(NULL, 0);
|
audioOutputPluginList = makeList(NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishAudioOutputPlugins(void) {
|
void finishAudioOutputPlugins(void)
|
||||||
|
{
|
||||||
freeList(audioOutputPluginList);
|
freeList(audioOutputPluginList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,52 +66,50 @@ void finishAudioOutputPlugins(void) {
|
|||||||
if(bp) str = bp->value; \
|
if(bp) str = bp->value; \
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioOutput * newAudioOutput(ConfigParam * param) {
|
AudioOutput *newAudioOutput(ConfigParam * param)
|
||||||
AudioOutput * ret = NULL;
|
{
|
||||||
void * data = NULL;
|
AudioOutput *ret = NULL;
|
||||||
char * name = NULL;
|
void *data = NULL;
|
||||||
char * format = NULL;
|
char *name = NULL;
|
||||||
char * type = NULL;
|
char *format = NULL;
|
||||||
BlockParam * bp = NULL;
|
char *type = NULL;
|
||||||
AudioOutputPlugin * plugin = NULL;
|
BlockParam *bp = NULL;
|
||||||
|
AudioOutputPlugin *plugin = NULL;
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
getBlockParam(AUDIO_OUTPUT_NAME, name, 1);
|
getBlockParam(AUDIO_OUTPUT_NAME, name, 1);
|
||||||
getBlockParam(AUDIO_OUTPUT_TYPE, type, 1);
|
getBlockParam(AUDIO_OUTPUT_TYPE, type, 1);
|
||||||
getBlockParam(AUDIO_OUTPUT_FORMAT, format, 0);
|
getBlockParam(AUDIO_OUTPUT_FORMAT, format, 0);
|
||||||
|
|
||||||
if(!findInList(audioOutputPluginList, type, &data)) {
|
if (!findInList(audioOutputPluginList, type, &data)) {
|
||||||
ERROR("couldn't find audio output plugin for type "
|
ERROR("couldn't find audio output plugin for type "
|
||||||
"\"%s\" at line %i\n", type,
|
"\"%s\" at line %i\n", type, param->line);
|
||||||
param->line);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
plugin = (AudioOutputPlugin *) data;
|
plugin = (AudioOutputPlugin *) data;
|
||||||
}
|
} else {
|
||||||
else {
|
ListNode *node = audioOutputPluginList->firstNode;
|
||||||
ListNode * node = audioOutputPluginList->firstNode;
|
|
||||||
|
|
||||||
WARNING("No \"%s\" defined in config file\n",
|
WARNING("No \"%s\" defined in config file\n",
|
||||||
CONF_AUDIO_OUTPUT);
|
CONF_AUDIO_OUTPUT);
|
||||||
WARNING("Attempt to detect audio output device\n");
|
WARNING("Attempt to detect audio output device\n");
|
||||||
|
|
||||||
while(node) {
|
while (node) {
|
||||||
plugin = (AudioOutputPlugin *) node->data;
|
plugin = (AudioOutputPlugin *) node->data;
|
||||||
if(plugin->testDefaultDeviceFunc) {
|
if (plugin->testDefaultDeviceFunc) {
|
||||||
WARNING("Attempting to detect a %s audio "
|
WARNING("Attempting to detect a %s audio "
|
||||||
"device\n", plugin->name);
|
"device\n", plugin->name);
|
||||||
if(plugin->testDefaultDeviceFunc() == 0) {
|
if (plugin->testDefaultDeviceFunc() == 0) {
|
||||||
WARNING("Successfully detected a %s "
|
WARNING("Successfully detected a %s "
|
||||||
"audio device\n",
|
"audio device\n", plugin->name);
|
||||||
plugin->name);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node = node->nextNode;
|
node = node->nextNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!node) {
|
if (!node) {
|
||||||
WARNING("Unable to detect an audio device\n");
|
WARNING("Unable to detect an audio device\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -134,20 +138,18 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
|
|||||||
memset(&ret->outAudioFormat, 0, sizeof(AudioFormat));
|
memset(&ret->outAudioFormat, 0, sizeof(AudioFormat));
|
||||||
memset(&ret->reqAudioFormat, 0, sizeof(AudioFormat));
|
memset(&ret->reqAudioFormat, 0, sizeof(AudioFormat));
|
||||||
|
|
||||||
if(format) {
|
if (format) {
|
||||||
ret->convertAudioFormat = 1;
|
ret->convertAudioFormat = 1;
|
||||||
|
|
||||||
if(0 != parseAudioConfig(&ret->reqAudioFormat, format))
|
if (0 != parseAudioConfig(&ret->reqAudioFormat, format)) {
|
||||||
{
|
ERROR("error parsing format at line %i\n", bp->line);
|
||||||
ERROR("error parsing format at line %i\n",
|
|
||||||
bp->line);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
copyAudioFormat(&ret->outAudioFormat, &ret->reqAudioFormat);
|
copyAudioFormat(&ret->outAudioFormat, &ret->reqAudioFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(plugin->initDriverFunc(ret, param) != 0) {
|
if (plugin->initDriverFunc(ret, param) != 0) {
|
||||||
free(ret);
|
free(ret);
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
}
|
}
|
||||||
@ -155,13 +157,13 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat) {
|
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat)
|
||||||
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if(audioOutput->open) {
|
if (audioOutput->open) {
|
||||||
if(cmpAudioFormat(audioFormat, &audioOutput->inAudioFormat)
|
if (cmpAudioFormat(audioFormat, &audioOutput->inAudioFormat)
|
||||||
== 0)
|
== 0) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
closeAudioOutput(audioOutput);
|
closeAudioOutput(audioOutput);
|
||||||
@ -169,35 +171,36 @@ int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat) {
|
|||||||
|
|
||||||
copyAudioFormat(&audioOutput->inAudioFormat, audioFormat);
|
copyAudioFormat(&audioOutput->inAudioFormat, audioFormat);
|
||||||
|
|
||||||
if(audioOutput->convertAudioFormat) {
|
if (audioOutput->convertAudioFormat) {
|
||||||
copyAudioFormat(&audioOutput->outAudioFormat,
|
copyAudioFormat(&audioOutput->outAudioFormat,
|
||||||
&audioOutput->reqAudioFormat);
|
&audioOutput->reqAudioFormat);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
copyAudioFormat(&audioOutput->outAudioFormat,
|
copyAudioFormat(&audioOutput->outAudioFormat,
|
||||||
&audioOutput->inAudioFormat);
|
&audioOutput->inAudioFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = audioOutput->openDeviceFunc(audioOutput);
|
ret = audioOutput->openDeviceFunc(audioOutput);
|
||||||
|
|
||||||
if(cmpAudioFormat(&audioOutput->inAudioFormat,
|
if (cmpAudioFormat(&audioOutput->inAudioFormat,
|
||||||
&audioOutput->outAudioFormat) == 0)
|
&audioOutput->outAudioFormat) == 0) {
|
||||||
{
|
|
||||||
audioOutput->sameInAndOutFormats = 1;
|
audioOutput->sameInAndOutFormats = 1;
|
||||||
}
|
} else
|
||||||
else audioOutput->sameInAndOutFormats = 0;
|
audioOutput->sameInAndOutFormats = 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void convertAudioFormat(AudioOutput * audioOutput, char ** chunkArgPtr,
|
static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr,
|
||||||
int * sizeArgPtr)
|
int *sizeArgPtr)
|
||||||
{
|
{
|
||||||
int size = pcm_sizeOfOutputBufferForAudioFormatConversion(
|
int size =
|
||||||
&(audioOutput->inAudioFormat), *sizeArgPtr,
|
pcm_sizeOfOutputBufferForAudioFormatConversion(&
|
||||||
&(audioOutput->outAudioFormat));
|
(audioOutput->
|
||||||
|
inAudioFormat),
|
||||||
|
*sizeArgPtr,
|
||||||
|
&(audioOutput->outAudioFormat));
|
||||||
|
|
||||||
if(size > audioOutput->convBufferLen) {
|
if (size > audioOutput->convBufferLen) {
|
||||||
audioOutput->convBuffer =
|
audioOutput->convBuffer =
|
||||||
realloc(audioOutput->convBuffer, size);
|
realloc(audioOutput->convBuffer, size);
|
||||||
audioOutput->convBufferLen = size;
|
audioOutput->convBufferLen = size;
|
||||||
@ -211,49 +214,59 @@ static void convertAudioFormat(AudioOutput * audioOutput, char ** chunkArgPtr,
|
|||||||
*chunkArgPtr = audioOutput->convBuffer;
|
*chunkArgPtr = audioOutput->convBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size) {
|
int playAudioOutput(AudioOutput * audioOutput, char *playChunk, int size)
|
||||||
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if(!audioOutput->open) return -1;
|
if (!audioOutput->open)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(!audioOutput->sameInAndOutFormats) {
|
if (!audioOutput->sameInAndOutFormats) {
|
||||||
convertAudioFormat(audioOutput, &playChunk, &size);
|
convertAudioFormat(audioOutput, &playChunk, &size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ret = audioOutput->playFunc(audioOutput, playChunk, size);
|
ret = audioOutput->playFunc(audioOutput, playChunk, size);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dropBufferedAudioOutput(AudioOutput * audioOutput) {
|
void dropBufferedAudioOutput(AudioOutput * audioOutput)
|
||||||
if(audioOutput->open) audioOutput->dropBufferedAudioFunc(audioOutput);
|
{
|
||||||
|
if (audioOutput->open)
|
||||||
|
audioOutput->dropBufferedAudioFunc(audioOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeAudioOutput(AudioOutput * audioOutput) {
|
void closeAudioOutput(AudioOutput * audioOutput)
|
||||||
if(audioOutput->open) audioOutput->closeDeviceFunc(audioOutput);
|
{
|
||||||
|
if (audioOutput->open)
|
||||||
|
audioOutput->closeDeviceFunc(audioOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishAudioOutput(AudioOutput * audioOutput) {
|
void finishAudioOutput(AudioOutput * audioOutput)
|
||||||
|
{
|
||||||
closeAudioOutput(audioOutput);
|
closeAudioOutput(audioOutput);
|
||||||
audioOutput->finishDriverFunc(audioOutput);
|
audioOutput->finishDriverFunc(audioOutput);
|
||||||
if(audioOutput->convBuffer) free(audioOutput->convBuffer);
|
if (audioOutput->convBuffer)
|
||||||
|
free(audioOutput->convBuffer);
|
||||||
free(audioOutput->type);
|
free(audioOutput->type);
|
||||||
free(audioOutput->name);
|
free(audioOutput->name);
|
||||||
free(audioOutput);
|
free(audioOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag) {
|
void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag)
|
||||||
if(!audioOutput->sendMetdataFunc) return;
|
{
|
||||||
|
if (!audioOutput->sendMetdataFunc)
|
||||||
|
return;
|
||||||
audioOutput->sendMetdataFunc(audioOutput, tag);
|
audioOutput->sendMetdataFunc(audioOutput, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printAllOutputPluginTypes(FILE *fp) {
|
void printAllOutputPluginTypes(FILE * fp)
|
||||||
|
{
|
||||||
ListNode *node = audioOutputPluginList->firstNode;
|
ListNode *node = audioOutputPluginList->firstNode;
|
||||||
AudioOutputPlugin *plugin;
|
AudioOutputPlugin *plugin;
|
||||||
|
|
||||||
while(node) {
|
while (node) {
|
||||||
plugin = (AudioOutputPlugin *)node->data;
|
plugin = (AudioOutputPlugin *) node->data;
|
||||||
myfprintf(fp, "%s ", plugin->name);
|
myfprintf(fp, "%s ", plugin->name);
|
||||||
node = node->nextNode;
|
node = node->nextNode;
|
||||||
}
|
}
|
||||||
|
@ -40,29 +40,29 @@
|
|||||||
|
|
||||||
typedef struct _AudioOutput AudioOutput;
|
typedef struct _AudioOutput AudioOutput;
|
||||||
|
|
||||||
typedef int (* AudioOutputTestDefaultDeviceFunc) ();
|
typedef int (*AudioOutputTestDefaultDeviceFunc) ();
|
||||||
|
|
||||||
typedef int (* AudioOutputInitDriverFunc) (AudioOutput * audioOutput,
|
typedef int (*AudioOutputInitDriverFunc) (AudioOutput * audioOutput,
|
||||||
ConfigParam * param);
|
ConfigParam * param);
|
||||||
|
|
||||||
typedef void (* AudioOutputFinishDriverFunc) (AudioOutput * audioOutput);
|
typedef void (*AudioOutputFinishDriverFunc) (AudioOutput * audioOutput);
|
||||||
|
|
||||||
typedef int (* AudioOutputOpenDeviceFunc) (AudioOutput * audioOutput);
|
typedef int (*AudioOutputOpenDeviceFunc) (AudioOutput * audioOutput);
|
||||||
|
|
||||||
typedef int (* AudioOutputPlayFunc) (AudioOutput * audioOutput,
|
typedef int (*AudioOutputPlayFunc) (AudioOutput * audioOutput,
|
||||||
char * playChunk, int size);
|
char *playChunk, int size);
|
||||||
|
|
||||||
typedef void (* AudioOutputDropBufferedAudioFunc) (AudioOutput * audioOutput);
|
typedef void (*AudioOutputDropBufferedAudioFunc) (AudioOutput * audioOutput);
|
||||||
|
|
||||||
typedef void (* AudioOutputCloseDeviceFunc) (AudioOutput * audioOutput);
|
typedef void (*AudioOutputCloseDeviceFunc) (AudioOutput * audioOutput);
|
||||||
|
|
||||||
typedef void (* AudioOutputSendMetadataFunc) (AudioOutput * audioOutput,
|
typedef void (*AudioOutputSendMetadataFunc) (AudioOutput * audioOutput,
|
||||||
MpdTag * tag);
|
MpdTag * tag);
|
||||||
|
|
||||||
struct _AudioOutput {
|
struct _AudioOutput {
|
||||||
int open;
|
int open;
|
||||||
char * name;
|
char *name;
|
||||||
char * type;
|
char *type;
|
||||||
|
|
||||||
AudioOutputFinishDriverFunc finishDriverFunc;
|
AudioOutputFinishDriverFunc finishDriverFunc;
|
||||||
AudioOutputOpenDeviceFunc openDeviceFunc;
|
AudioOutputOpenDeviceFunc openDeviceFunc;
|
||||||
@ -75,15 +75,15 @@ struct _AudioOutput {
|
|||||||
AudioFormat inAudioFormat;
|
AudioFormat inAudioFormat;
|
||||||
AudioFormat outAudioFormat;
|
AudioFormat outAudioFormat;
|
||||||
AudioFormat reqAudioFormat;
|
AudioFormat reqAudioFormat;
|
||||||
char * convBuffer;
|
char *convBuffer;
|
||||||
int convBufferLen;
|
int convBufferLen;
|
||||||
int sameInAndOutFormats;
|
int sameInAndOutFormats;
|
||||||
|
|
||||||
void * data;
|
void *data;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _AudioOutputPlugin {
|
typedef struct _AudioOutputPlugin {
|
||||||
char * name;
|
char *name;
|
||||||
|
|
||||||
AudioOutputTestDefaultDeviceFunc testDefaultDeviceFunc;
|
AudioOutputTestDefaultDeviceFunc testDefaultDeviceFunc;
|
||||||
AudioOutputInitDriverFunc initDriverFunc;
|
AudioOutputInitDriverFunc initDriverFunc;
|
||||||
@ -101,14 +101,14 @@ void finishAudioOutputPlugins();
|
|||||||
void loadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
|
void loadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
|
||||||
void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
|
void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
|
||||||
|
|
||||||
AudioOutput * newAudioOutput(ConfigParam * param);
|
AudioOutput *newAudioOutput(ConfigParam * param);
|
||||||
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat);
|
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat);
|
||||||
int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size);
|
int playAudioOutput(AudioOutput * audioOutput, char *playChunk, int size);
|
||||||
void dropBufferedAudioOutput(AudioOutput * audioOutput);
|
void dropBufferedAudioOutput(AudioOutput * audioOutput);
|
||||||
void closeAudioOutput(AudioOutput * audioOutput);
|
void closeAudioOutput(AudioOutput * audioOutput);
|
||||||
void finishAudioOutput(AudioOutput * audioOutput);
|
void finishAudioOutput(AudioOutput * audioOutput);
|
||||||
int keepAudioOutputAlive(AudioOutput * audioOutput, int ms);
|
int keepAudioOutputAlive(AudioOutput * audioOutput, int ms);
|
||||||
void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag);
|
void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag);
|
||||||
|
|
||||||
void printAllOutputPluginTypes(FILE *fp);
|
void printAllOutputPluginTypes(FILE * fp);
|
||||||
#endif
|
#endif
|
||||||
|
@ -39,13 +39,13 @@
|
|||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t *pcm, const void *buffer,
|
typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t * pcm, const void *buffer,
|
||||||
snd_pcm_uframes_t size);
|
snd_pcm_uframes_t size);
|
||||||
|
|
||||||
typedef struct _AlsaData {
|
typedef struct _AlsaData {
|
||||||
char * device;
|
char *device;
|
||||||
snd_pcm_t * pcmHandle;
|
snd_pcm_t *pcmHandle;
|
||||||
alsa_writei_t * writei;
|
alsa_writei_t *writei;
|
||||||
unsigned int buffer_time;
|
unsigned int buffer_time;
|
||||||
unsigned int period_time;
|
unsigned int period_time;
|
||||||
int sampleSize;
|
int sampleSize;
|
||||||
@ -54,8 +54,9 @@ typedef struct _AlsaData {
|
|||||||
int canResume;
|
int canResume;
|
||||||
} AlsaData;
|
} AlsaData;
|
||||||
|
|
||||||
static AlsaData * newAlsaData(void) {
|
static AlsaData *newAlsaData(void)
|
||||||
AlsaData * ret = malloc(sizeof(AlsaData));
|
{
|
||||||
|
AlsaData *ret = malloc(sizeof(AlsaData));
|
||||||
|
|
||||||
ret->device = NULL;
|
ret->device = NULL;
|
||||||
ret->pcmHandle = NULL;
|
ret->pcmHandle = NULL;
|
||||||
@ -67,17 +68,20 @@ static AlsaData * newAlsaData(void) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeAlsaData(AlsaData * ad) {
|
static void freeAlsaData(AlsaData * ad)
|
||||||
if(ad->device) free(ad->device);
|
{
|
||||||
|
if (ad->device)
|
||||||
|
free(ad->device);
|
||||||
|
|
||||||
free(ad);
|
free(ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alsa_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
static int alsa_initDriver(AudioOutput * audioOutput, ConfigParam * param)
|
||||||
AlsaData * ad = newAlsaData();
|
{
|
||||||
|
AlsaData *ad = newAlsaData();
|
||||||
|
|
||||||
if (param) {
|
if (param) {
|
||||||
BlockParam * bp = getBlockParam(param, "device");
|
BlockParam *bp = getBlockParam(param, "device");
|
||||||
ad->device = bp ? strdup(bp->value) : strdup("default");
|
ad->device = bp ? strdup(bp->value) : strdup("default");
|
||||||
|
|
||||||
if ((bp = getBlockParam(param, "use_mmap")) &&
|
if ((bp = getBlockParam(param, "use_mmap")) &&
|
||||||
@ -94,45 +98,46 @@ static int alsa_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alsa_finishDriver(AudioOutput * audioOutput) {
|
static void alsa_finishDriver(AudioOutput * audioOutput)
|
||||||
AlsaData * ad = audioOutput->data;
|
{
|
||||||
|
AlsaData *ad = audioOutput->data;
|
||||||
|
|
||||||
freeAlsaData(ad);
|
freeAlsaData(ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alsa_testDefault(void)
|
static int alsa_testDefault(void)
|
||||||
{
|
{
|
||||||
snd_pcm_t * handle;
|
snd_pcm_t *handle;
|
||||||
|
|
||||||
int ret = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK,
|
int ret = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK,
|
||||||
SND_PCM_NONBLOCK);
|
SND_PCM_NONBLOCK);
|
||||||
snd_config_update_free_global();
|
snd_config_update_free_global();
|
||||||
|
|
||||||
if(ret) {
|
if (ret) {
|
||||||
WARNING("Error opening default alsa device: %s\n",
|
WARNING("Error opening default alsa device: %s\n",
|
||||||
snd_strerror(-ret));
|
snd_strerror(-ret));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else
|
||||||
else snd_pcm_close(handle);
|
snd_pcm_close(handle);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alsa_openDevice(AudioOutput * audioOutput)
|
static int alsa_openDevice(AudioOutput * audioOutput)
|
||||||
{
|
{
|
||||||
AlsaData * ad = audioOutput->data;
|
AlsaData *ad = audioOutput->data;
|
||||||
AudioFormat * audioFormat = &audioOutput->outAudioFormat;
|
AudioFormat *audioFormat = &audioOutput->outAudioFormat;
|
||||||
snd_pcm_format_t bitformat;
|
snd_pcm_format_t bitformat;
|
||||||
snd_pcm_hw_params_t * hwparams;
|
snd_pcm_hw_params_t *hwparams;
|
||||||
snd_pcm_sw_params_t * swparams;
|
snd_pcm_sw_params_t *swparams;
|
||||||
unsigned int sampleRate = audioFormat->sampleRate;
|
unsigned int sampleRate = audioFormat->sampleRate;
|
||||||
unsigned int channels = audioFormat->channels;
|
unsigned int channels = audioFormat->channels;
|
||||||
snd_pcm_uframes_t alsa_buffer_size;
|
snd_pcm_uframes_t alsa_buffer_size;
|
||||||
snd_pcm_uframes_t alsa_period_size;
|
snd_pcm_uframes_t alsa_period_size;
|
||||||
int err;
|
int err;
|
||||||
char * cmd = NULL;
|
char *cmd = NULL;
|
||||||
|
|
||||||
switch(audioFormat->bits) {
|
switch (audioFormat->bits) {
|
||||||
case 8:
|
case 8:
|
||||||
bitformat = SND_PCM_FORMAT_S8;
|
bitformat = SND_PCM_FORMAT_S8;
|
||||||
break;
|
break;
|
||||||
@ -154,54 +159,55 @@ static int alsa_openDevice(AudioOutput * audioOutput)
|
|||||||
err = snd_pcm_open(&ad->pcmHandle, ad->device,
|
err = snd_pcm_open(&ad->pcmHandle, ad->device,
|
||||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||||
snd_config_update_free_global();
|
snd_config_update_free_global();
|
||||||
if(err < 0) {
|
if (err < 0) {
|
||||||
ad->pcmHandle = NULL;
|
ad->pcmHandle = NULL;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = "snd_pcm_nonblock";
|
cmd = "snd_pcm_nonblock";
|
||||||
err = snd_pcm_nonblock(ad->pcmHandle, 0);
|
err = snd_pcm_nonblock(ad->pcmHandle, 0);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
/* configure HW params */
|
/* configure HW params */
|
||||||
snd_pcm_hw_params_alloca(&hwparams);
|
snd_pcm_hw_params_alloca(&hwparams);
|
||||||
|
|
||||||
cmd = "snd_pcm_hw_params_any";
|
cmd = "snd_pcm_hw_params_any";
|
||||||
err = snd_pcm_hw_params_any(ad->pcmHandle, hwparams);
|
err = snd_pcm_hw_params_any(ad->pcmHandle, hwparams);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
if(ad->useMmap) {
|
if (ad->useMmap) {
|
||||||
err = snd_pcm_hw_params_set_access(ad->pcmHandle, hwparams,
|
err = snd_pcm_hw_params_set_access(ad->pcmHandle, hwparams,
|
||||||
SND_PCM_ACCESS_MMAP_INTERLEAVED);
|
SND_PCM_ACCESS_MMAP_INTERLEAVED);
|
||||||
if(err < 0) {
|
if (err < 0) {
|
||||||
ERROR("Cannot set mmap'ed mode on alsa device \"%s\": "
|
ERROR("Cannot set mmap'ed mode on alsa device \"%s\": "
|
||||||
" %s\n", ad->device,
|
" %s\n", ad->device, snd_strerror(-err));
|
||||||
snd_strerror(-err));
|
|
||||||
ERROR("Falling back to direct write mode\n");
|
ERROR("Falling back to direct write mode\n");
|
||||||
ad->useMmap = 0;
|
ad->useMmap = 0;
|
||||||
}
|
} else
|
||||||
else ad->writei = snd_pcm_mmap_writei;
|
ad->writei = snd_pcm_mmap_writei;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ad->useMmap) {
|
if (!ad->useMmap) {
|
||||||
cmd = "snd_pcm_hw_params_set_access";
|
cmd = "snd_pcm_hw_params_set_access";
|
||||||
err = snd_pcm_hw_params_set_access(ad->pcmHandle, hwparams,
|
err = snd_pcm_hw_params_set_access(ad->pcmHandle, hwparams,
|
||||||
SND_PCM_ACCESS_RW_INTERLEAVED);
|
SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
ad->writei = snd_pcm_writei;
|
ad->writei = snd_pcm_writei;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_format(ad->pcmHandle, hwparams, bitformat);
|
err = snd_pcm_hw_params_set_format(ad->pcmHandle, hwparams, bitformat);
|
||||||
if(err < 0) {
|
if (err < 0) {
|
||||||
ERROR("Alsa device \"%s\" does not support %i bit audio: "
|
ERROR("Alsa device \"%s\" does not support %i bit audio: "
|
||||||
"%s\n", ad->device, (int)bitformat,
|
"%s\n", ad->device, (int)bitformat, snd_strerror(-err));
|
||||||
snd_strerror(-err));
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_hw_params_set_channels_near(ad->pcmHandle, hwparams,
|
err = snd_pcm_hw_params_set_channels_near(ad->pcmHandle, hwparams,
|
||||||
&channels);
|
&channels);
|
||||||
if(err < 0) {
|
if (err < 0) {
|
||||||
ERROR("Alsa device \"%s\" does not support %i channels: "
|
ERROR("Alsa device \"%s\" does not support %i channels: "
|
||||||
"%s\n", ad->device, (int)audioFormat->channels,
|
"%s\n", ad->device, (int)audioFormat->channels,
|
||||||
snd_strerror(-err));
|
snd_strerror(-err));
|
||||||
@ -211,7 +217,7 @@ static int alsa_openDevice(AudioOutput * audioOutput)
|
|||||||
|
|
||||||
err = snd_pcm_hw_params_set_rate_near(ad->pcmHandle, hwparams,
|
err = snd_pcm_hw_params_set_rate_near(ad->pcmHandle, hwparams,
|
||||||
&sampleRate, NULL);
|
&sampleRate, NULL);
|
||||||
if(err < 0 || sampleRate == 0) {
|
if (err < 0 || sampleRate == 0) {
|
||||||
ERROR("Alsa device \"%s\" does not support %i Hz audio\n",
|
ERROR("Alsa device \"%s\" does not support %i Hz audio\n",
|
||||||
ad->device, (int)audioFormat->sampleRate);
|
ad->device, (int)audioFormat->sampleRate);
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -221,27 +227,32 @@ static int alsa_openDevice(AudioOutput * audioOutput)
|
|||||||
cmd = "snd_pcm_hw_params_set_buffer_time_near";
|
cmd = "snd_pcm_hw_params_set_buffer_time_near";
|
||||||
err = snd_pcm_hw_params_set_buffer_time_near(ad->pcmHandle, hwparams,
|
err = snd_pcm_hw_params_set_buffer_time_near(ad->pcmHandle, hwparams,
|
||||||
&ad->buffer_time, NULL);
|
&ad->buffer_time, NULL);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
if (!ad->period_time && sampleRate > 0)
|
if (!ad->period_time && sampleRate > 0)
|
||||||
ad->period_time = 1000000 * MPD_ALSA_SAMPLE_XFER / sampleRate;
|
ad->period_time = 1000000 * MPD_ALSA_SAMPLE_XFER / sampleRate;
|
||||||
cmd = "snd_pcm_hw_params_set_period_time_near";
|
cmd = "snd_pcm_hw_params_set_period_time_near";
|
||||||
err = snd_pcm_hw_params_set_period_time_near(ad->pcmHandle, hwparams,
|
err = snd_pcm_hw_params_set_period_time_near(ad->pcmHandle, hwparams,
|
||||||
&ad->period_time, NULL);
|
&ad->period_time, NULL);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
cmd = "snd_pcm_hw_params";
|
cmd = "snd_pcm_hw_params";
|
||||||
err = snd_pcm_hw_params(ad->pcmHandle, hwparams);
|
err = snd_pcm_hw_params(ad->pcmHandle, hwparams);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
cmd = "snd_pcm_hw_params_get_buffer_size";
|
cmd = "snd_pcm_hw_params_get_buffer_size";
|
||||||
err = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa_buffer_size);
|
err = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa_buffer_size);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
cmd = "snd_pcm_hw_params_get_period_size";
|
cmd = "snd_pcm_hw_params_get_period_size";
|
||||||
err = snd_pcm_hw_params_get_period_size(hwparams, &alsa_period_size,
|
err = snd_pcm_hw_params_get_period_size(hwparams, &alsa_period_size,
|
||||||
NULL);
|
NULL);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
ad->canPause = snd_pcm_hw_params_can_pause(hwparams);
|
ad->canPause = snd_pcm_hw_params_can_pause(hwparams);
|
||||||
ad->canResume = snd_pcm_hw_params_can_resume(hwparams);
|
ad->canResume = snd_pcm_hw_params_can_resume(hwparams);
|
||||||
@ -251,27 +262,33 @@ static int alsa_openDevice(AudioOutput * audioOutput)
|
|||||||
|
|
||||||
cmd = "snd_pcm_sw_params_current";
|
cmd = "snd_pcm_sw_params_current";
|
||||||
err = snd_pcm_sw_params_current(ad->pcmHandle, swparams);
|
err = snd_pcm_sw_params_current(ad->pcmHandle, swparams);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
cmd = "snd_pcm_sw_params_set_start_threshold";
|
cmd = "snd_pcm_sw_params_set_start_threshold";
|
||||||
err = snd_pcm_sw_params_set_start_threshold(ad->pcmHandle, swparams,
|
err = snd_pcm_sw_params_set_start_threshold(ad->pcmHandle, swparams,
|
||||||
alsa_buffer_size - alsa_period_size);
|
alsa_buffer_size -
|
||||||
if(err < 0) goto error;
|
alsa_period_size);
|
||||||
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
cmd = "snd_pcm_sw_params_set_avail_min";
|
cmd = "snd_pcm_sw_params_set_avail_min";
|
||||||
err = snd_pcm_sw_params_set_avail_min(ad->pcmHandle, swparams,
|
err = snd_pcm_sw_params_set_avail_min(ad->pcmHandle, swparams,
|
||||||
alsa_period_size);
|
alsa_period_size);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
cmd = "snd_pcm_sw_params_set_xfer_align";
|
cmd = "snd_pcm_sw_params_set_xfer_align";
|
||||||
err = snd_pcm_sw_params_set_xfer_align(ad->pcmHandle, swparams, 1);
|
err = snd_pcm_sw_params_set_xfer_align(ad->pcmHandle, swparams, 1);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
cmd = "snd_pcm_sw_params";
|
cmd = "snd_pcm_sw_params";
|
||||||
err = snd_pcm_sw_params(ad->pcmHandle, swparams);
|
err = snd_pcm_sw_params(ad->pcmHandle, swparams);
|
||||||
if(err < 0) goto error;
|
if (err < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
ad->sampleSize = (audioFormat->bits/8)*audioFormat->channels;
|
ad->sampleSize = (audioFormat->bits / 8) * audioFormat->channels;
|
||||||
|
|
||||||
audioOutput->open = 1;
|
audioOutput->open = 1;
|
||||||
|
|
||||||
@ -281,31 +298,31 @@ static int alsa_openDevice(AudioOutput * audioOutput)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if(cmd) {
|
if (cmd) {
|
||||||
ERROR("Error opening alsa device \"%s\" (%s): %s\n",
|
ERROR("Error opening alsa device \"%s\" (%s): %s\n",
|
||||||
ad->device, cmd, snd_strerror(-err));
|
ad->device, cmd, snd_strerror(-err));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ERROR("Error opening alsa device \"%s\": %s\n", ad->device,
|
ERROR("Error opening alsa device \"%s\": %s\n", ad->device,
|
||||||
snd_strerror(-err));
|
snd_strerror(-err));
|
||||||
}
|
}
|
||||||
fail:
|
fail:
|
||||||
if(ad->pcmHandle) snd_pcm_close(ad->pcmHandle);
|
if (ad->pcmHandle)
|
||||||
|
snd_pcm_close(ad->pcmHandle);
|
||||||
ad->pcmHandle = NULL;
|
ad->pcmHandle = NULL;
|
||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alsa_errorRecovery(AlsaData * ad, int err) {
|
static int alsa_errorRecovery(AlsaData * ad, int err)
|
||||||
if(err == -EPIPE) {
|
{
|
||||||
|
if (err == -EPIPE) {
|
||||||
DEBUG("Underrun on alsa device \"%s\"\n", ad->device);
|
DEBUG("Underrun on alsa device \"%s\"\n", ad->device);
|
||||||
}
|
} else if (err == -ESTRPIPE) {
|
||||||
else if(err == -ESTRPIPE) {
|
|
||||||
DEBUG("alsa device \"%s\" was suspended\n", ad->device);
|
DEBUG("alsa device \"%s\" was suspended\n", ad->device);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(snd_pcm_state(ad->pcmHandle)) {
|
switch (snd_pcm_state(ad->pcmHandle)) {
|
||||||
case SND_PCM_STATE_PAUSED:
|
case SND_PCM_STATE_PAUSED:
|
||||||
err = snd_pcm_pause(ad->pcmHandle, /* disable */ 0);
|
err = snd_pcm_pause(ad->pcmHandle, /* disable */ 0);
|
||||||
break;
|
break;
|
||||||
@ -331,16 +348,18 @@ static int alsa_errorRecovery(AlsaData * ad, int err) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alsa_dropBufferedAudio(AudioOutput * audioOutput) {
|
static void alsa_dropBufferedAudio(AudioOutput * audioOutput)
|
||||||
AlsaData * ad = audioOutput->data;
|
{
|
||||||
|
AlsaData *ad = audioOutput->data;
|
||||||
|
|
||||||
alsa_errorRecovery( ad, snd_pcm_drop(ad->pcmHandle) );
|
alsa_errorRecovery(ad, snd_pcm_drop(ad->pcmHandle));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alsa_closeDevice(AudioOutput * audioOutput) {
|
static void alsa_closeDevice(AudioOutput * audioOutput)
|
||||||
AlsaData * ad = audioOutput->data;
|
{
|
||||||
|
AlsaData *ad = audioOutput->data;
|
||||||
|
|
||||||
if(ad->pcmHandle) {
|
if (ad->pcmHandle) {
|
||||||
snd_pcm_drain(ad->pcmHandle);
|
snd_pcm_drain(ad->pcmHandle);
|
||||||
snd_pcm_close(ad->pcmHandle);
|
snd_pcm_close(ad->pcmHandle);
|
||||||
ad->pcmHandle = NULL;
|
ad->pcmHandle = NULL;
|
||||||
@ -349,10 +368,9 @@ static void alsa_closeDevice(AudioOutput * audioOutput) {
|
|||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int alsa_playAudio(AudioOutput * audioOutput, char * playChunk,
|
static int alsa_playAudio(AudioOutput * audioOutput, char *playChunk, int size)
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
AlsaData * ad = audioOutput->data;
|
AlsaData *ad = audioOutput->data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
size /= ad->sampleSize;
|
size /= ad->sampleSize;
|
||||||
@ -360,10 +378,11 @@ static int alsa_playAudio(AudioOutput * audioOutput, char * playChunk,
|
|||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
ret = ad->writei(ad->pcmHandle, playChunk, size);
|
ret = ad->writei(ad->pcmHandle, playChunk, size);
|
||||||
|
|
||||||
if(ret == -EAGAIN || ret == -EINTR) continue;
|
if (ret == -EAGAIN || ret == -EINTR)
|
||||||
|
continue;
|
||||||
|
|
||||||
if(ret < 0) {
|
if (ret < 0) {
|
||||||
if( alsa_errorRecovery(ad, ret) < 0) {
|
if (alsa_errorRecovery(ad, ret) < 0) {
|
||||||
ERROR("closing alsa device \"%s\" due to write "
|
ERROR("closing alsa device \"%s\" due to write "
|
||||||
"error: %s\n", ad->device,
|
"error: %s\n", ad->device,
|
||||||
snd_strerror(-errno));
|
snd_strerror(-errno));
|
||||||
@ -380,8 +399,7 @@ static int alsa_playAudio(AudioOutput * audioOutput, char * playChunk,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioOutputPlugin alsaPlugin =
|
AudioOutputPlugin alsaPlugin = {
|
||||||
{
|
|
||||||
"alsa",
|
"alsa",
|
||||||
alsa_testDefault,
|
alsa_testDefault,
|
||||||
alsa_initDriver,
|
alsa_initDriver,
|
||||||
@ -396,5 +414,4 @@ AudioOutputPlugin alsaPlugin =
|
|||||||
#else /* HAVE ALSA */
|
#else /* HAVE ALSA */
|
||||||
|
|
||||||
DISABLED_AUDIO_OUTPUT_PLUGIN(alsaPlugin)
|
DISABLED_AUDIO_OUTPUT_PLUGIN(alsaPlugin)
|
||||||
|
|
||||||
#endif /* HAVE_ALSA */
|
#endif /* HAVE_ALSA */
|
||||||
|
@ -34,26 +34,26 @@ static int driverInitCount = 0;
|
|||||||
typedef struct _AoData {
|
typedef struct _AoData {
|
||||||
int writeSize;
|
int writeSize;
|
||||||
int driverId;
|
int driverId;
|
||||||
ao_option * options;
|
ao_option *options;
|
||||||
ao_device * device;
|
ao_device *device;
|
||||||
} AoData;
|
} AoData;
|
||||||
|
|
||||||
static AoData * newAoData() {
|
static AoData *newAoData()
|
||||||
AoData * ret = malloc(sizeof(AoData));
|
{
|
||||||
|
AoData *ret = malloc(sizeof(AoData));
|
||||||
ret->device = NULL;
|
ret->device = NULL;
|
||||||
ret->options = NULL;
|
ret->options = NULL;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audioOutputAo_error() {
|
static void audioOutputAo_error()
|
||||||
if(errno==AO_ENOTLIVE) {
|
{
|
||||||
|
if (errno == AO_ENOTLIVE) {
|
||||||
ERROR("not a live ao device\n");
|
ERROR("not a live ao device\n");
|
||||||
}
|
} else if (errno == AO_EOPENDEVICE) {
|
||||||
else if(errno==AO_EOPENDEVICE) {
|
|
||||||
ERROR("not able to open audio device\n");
|
ERROR("not able to open audio device\n");
|
||||||
}
|
} else if (errno == AO_EBADOPTION) {
|
||||||
else if(errno==AO_EBADOPTION) {
|
|
||||||
ERROR("bad driver option\n");
|
ERROR("bad driver option\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,47 +61,45 @@ static void audioOutputAo_error() {
|
|||||||
static int audioOutputAo_initDriver(AudioOutput * audioOutput,
|
static int audioOutputAo_initDriver(AudioOutput * audioOutput,
|
||||||
ConfigParam * param)
|
ConfigParam * param)
|
||||||
{
|
{
|
||||||
ao_info * ai;
|
ao_info *ai;
|
||||||
char * dup;
|
char *dup;
|
||||||
char * stk1;
|
char *stk1;
|
||||||
char * stk2;
|
char *stk2;
|
||||||
char * n1;
|
char *n1;
|
||||||
char * key;
|
char *key;
|
||||||
char * value;
|
char *value;
|
||||||
char * test;
|
char *test;
|
||||||
AoData * ad = newAoData();
|
AoData *ad = newAoData();
|
||||||
BlockParam * blockParam;
|
BlockParam *blockParam;
|
||||||
|
|
||||||
audioOutput->data = ad;
|
audioOutput->data = ad;
|
||||||
|
|
||||||
if((blockParam = getBlockParam(param, "write_size"))) {
|
if ((blockParam = getBlockParam(param, "write_size"))) {
|
||||||
ad->writeSize = strtol(blockParam->value, &test, 10);
|
ad->writeSize = strtol(blockParam->value, &test, 10);
|
||||||
if (*test!='\0') {
|
if (*test != '\0') {
|
||||||
ERROR("\"%s\" is not a valid write size at line %i\n",
|
ERROR("\"%s\" is not a valid write size at line %i\n",
|
||||||
blockParam->value, blockParam->line);
|
blockParam->value, blockParam->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else ad->writeSize = 1024;
|
ad->writeSize = 1024;
|
||||||
|
|
||||||
if(driverInitCount == 0) {
|
if (driverInitCount == 0) {
|
||||||
ao_initialize();
|
ao_initialize();
|
||||||
}
|
}
|
||||||
driverInitCount++;
|
driverInitCount++;
|
||||||
|
|
||||||
blockParam = getBlockParam(param, "driver");
|
blockParam = getBlockParam(param, "driver");
|
||||||
|
|
||||||
if(!blockParam || 0 == strcmp(blockParam->value,"default")) {
|
if (!blockParam || 0 == strcmp(blockParam->value, "default")) {
|
||||||
ad->driverId = ao_default_driver_id();
|
ad->driverId = ao_default_driver_id();
|
||||||
}
|
} else if ((ad->driverId = ao_driver_id(blockParam->value)) < 0) {
|
||||||
else if((ad->driverId =
|
|
||||||
ao_driver_id(blockParam->value))<0) {
|
|
||||||
ERROR("\"%s\" is not a valid ao driver at line %i\n",
|
ERROR("\"%s\" is not a valid ao driver at line %i\n",
|
||||||
blockParam->value, blockParam->line);
|
blockParam->value, blockParam->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((ai = ao_driver_info(ad->driverId))==NULL) {
|
if ((ai = ao_driver_info(ad->driverId)) == NULL) {
|
||||||
ERROR("problems getting driver info for device defined at "
|
ERROR("problems getting driver info for device defined at "
|
||||||
"line %i\n", param->line);
|
"line %i\n", param->line);
|
||||||
ERROR("you may not have permission to the audio device\n");
|
ERROR("you may not have permission to the audio device\n");
|
||||||
@ -113,18 +111,18 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
|
|||||||
|
|
||||||
blockParam = getBlockParam(param, "options");
|
blockParam = getBlockParam(param, "options");
|
||||||
|
|
||||||
if(blockParam) {
|
if (blockParam) {
|
||||||
dup = strdup(blockParam->value);
|
dup = strdup(blockParam->value);
|
||||||
}
|
} else
|
||||||
else dup = strdup("");
|
dup = strdup("");
|
||||||
|
|
||||||
if(strlen(dup)) {
|
if (strlen(dup)) {
|
||||||
stk1 = NULL;
|
stk1 = NULL;
|
||||||
n1 = strtok_r(dup,";",&stk1);
|
n1 = strtok_r(dup, ";", &stk1);
|
||||||
while(n1) {
|
while (n1) {
|
||||||
stk2 = NULL;
|
stk2 = NULL;
|
||||||
key = strtok_r(n1,"=",&stk2);
|
key = strtok_r(n1, "=", &stk2);
|
||||||
if(!key) {
|
if (!key) {
|
||||||
ERROR("problems parsing "
|
ERROR("problems parsing "
|
||||||
"ao_driver_options \"%s\"\n", n1);
|
"ao_driver_options \"%s\"\n", n1);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -141,15 +139,15 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
|
|||||||
"\"%s\" ao driver\n",key,
|
"\"%s\" ao driver\n",key,
|
||||||
ai->short_name);
|
ai->short_name);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}*/
|
} */
|
||||||
value = strtok_r(NULL,"",&stk2);
|
value = strtok_r(NULL, "", &stk2);
|
||||||
if(!value) {
|
if (!value) {
|
||||||
ERROR("problems parsing "
|
ERROR("problems parsing "
|
||||||
"ao_driver_options \"%s\"\n", n1);
|
"ao_driver_options \"%s\"\n", n1);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
ao_append_option(&ad->options,key,value);
|
ao_append_option(&ad->options, key, value);
|
||||||
n1 = strtok_r(NULL,";",&stk1);
|
n1 = strtok_r(NULL, ";", &stk1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(dup);
|
free(dup);
|
||||||
@ -157,28 +155,33 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeAoData(AoData * ad) {
|
static void freeAoData(AoData * ad)
|
||||||
|
{
|
||||||
ao_free_options(ad->options);
|
ao_free_options(ad->options);
|
||||||
free(ad);
|
free(ad);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audioOutputAo_finishDriver(AudioOutput * audioOutput) {
|
static void audioOutputAo_finishDriver(AudioOutput * audioOutput)
|
||||||
AoData * ad = (AoData *)audioOutput->data;
|
{
|
||||||
|
AoData *ad = (AoData *) audioOutput->data;
|
||||||
freeAoData(ad);
|
freeAoData(ad);
|
||||||
|
|
||||||
driverInitCount--;
|
driverInitCount--;
|
||||||
|
|
||||||
if(driverInitCount == 0) ao_shutdown();
|
if (driverInitCount == 0)
|
||||||
|
ao_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audioOutputAo_dropBufferedAudio(AudioOutput * audioOutput) {
|
static void audioOutputAo_dropBufferedAudio(AudioOutput * audioOutput)
|
||||||
|
{
|
||||||
/* not supported by libao */
|
/* not supported by libao */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audioOutputAo_closeDevice(AudioOutput * audioOutput) {
|
static void audioOutputAo_closeDevice(AudioOutput * audioOutput)
|
||||||
AoData * ad = (AoData *) audioOutput->data;
|
{
|
||||||
|
AoData *ad = (AoData *) audioOutput->data;
|
||||||
|
|
||||||
if(ad->device) {
|
if (ad->device) {
|
||||||
ao_close(ad->device);
|
ao_close(ad->device);
|
||||||
ad->device = NULL;
|
ad->device = NULL;
|
||||||
}
|
}
|
||||||
@ -186,11 +189,12 @@ static void audioOutputAo_closeDevice(AudioOutput * audioOutput) {
|
|||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int audioOutputAo_openDevice(AudioOutput * audioOutput) {
|
static int audioOutputAo_openDevice(AudioOutput * audioOutput)
|
||||||
|
{
|
||||||
ao_sample_format format;
|
ao_sample_format format;
|
||||||
AoData * ad = (AoData *)audioOutput->data;
|
AoData *ad = (AoData *) audioOutput->data;
|
||||||
|
|
||||||
if(ad->device) {
|
if (ad->device) {
|
||||||
audioOutputAo_closeDevice(audioOutput);
|
audioOutputAo_closeDevice(audioOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,41 +205,41 @@ static int audioOutputAo_openDevice(AudioOutput * audioOutput) {
|
|||||||
|
|
||||||
ad->device = ao_open_live(ad->driverId, &format, ad->options);
|
ad->device = ao_open_live(ad->driverId, &format, ad->options);
|
||||||
|
|
||||||
if(ad->device==NULL) return -1;
|
if (ad->device == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
audioOutput->open = 1;
|
audioOutput->open = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int audioOutputAo_play(AudioOutput * audioOutput, char *playChunk,
|
||||||
static int audioOutputAo_play(AudioOutput * audioOutput, char * playChunk,
|
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
int send;
|
int send;
|
||||||
AoData * ad = (AoData *)audioOutput->data;
|
AoData *ad = (AoData *) audioOutput->data;
|
||||||
|
|
||||||
if(ad->device==NULL) return -1;
|
if (ad->device == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
while(size>0) {
|
while (size > 0) {
|
||||||
send = ad->writeSize > size ? size : ad->writeSize;
|
send = ad->writeSize > size ? size : ad->writeSize;
|
||||||
|
|
||||||
if(ao_play(ad->device, playChunk, send)==0) {
|
if (ao_play(ad->device, playChunk, send) == 0) {
|
||||||
audioOutputAo_error();
|
audioOutputAo_error();
|
||||||
ERROR("closing audio device due to write error\n");
|
ERROR("closing audio device due to write error\n");
|
||||||
audioOutputAo_closeDevice(audioOutput);
|
audioOutputAo_closeDevice(audioOutput);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
playChunk+=send;
|
playChunk += send;
|
||||||
size-=send;
|
size -= send;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioOutputPlugin aoPlugin =
|
AudioOutputPlugin aoPlugin = {
|
||||||
{
|
|
||||||
"ao",
|
"ao",
|
||||||
NULL,
|
NULL,
|
||||||
audioOutputAo_initDriver,
|
audioOutputAo_initDriver,
|
||||||
@ -252,5 +256,4 @@ AudioOutputPlugin aoPlugin =
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
DISABLED_AUDIO_OUTPUT_PLUGIN(aoPlugin)
|
DISABLED_AUDIO_OUTPUT_PLUGIN(aoPlugin)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -54,14 +54,14 @@
|
|||||||
|
|
||||||
typedef struct _OssData {
|
typedef struct _OssData {
|
||||||
int fd;
|
int fd;
|
||||||
char * device;
|
char *device;
|
||||||
int channels;
|
int channels;
|
||||||
int sampleRate;
|
int sampleRate;
|
||||||
int bitFormat;
|
int bitFormat;
|
||||||
int bits;
|
int bits;
|
||||||
int * supported[3];
|
int *supported[3];
|
||||||
int numSupported[3];
|
int numSupported[3];
|
||||||
int * unsupported[3];
|
int *unsupported[3];
|
||||||
int numUnsupported[3];
|
int numUnsupported[3];
|
||||||
} OssData;
|
} OssData;
|
||||||
|
|
||||||
@ -73,10 +73,11 @@ typedef struct _OssData {
|
|||||||
#define OSS_CHANNELS 1
|
#define OSS_CHANNELS 1
|
||||||
#define OSS_BITS 2
|
#define OSS_BITS 2
|
||||||
|
|
||||||
static int getIndexForParam(int param) {
|
static int getIndexForParam(int param)
|
||||||
|
{
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
switch(param) {
|
switch (param) {
|
||||||
case SNDCTL_DSP_SPEED:
|
case SNDCTL_DSP_SPEED:
|
||||||
index = OSS_RATE;
|
index = OSS_RATE;
|
||||||
break;
|
break;
|
||||||
@ -91,42 +92,49 @@ static int getIndexForParam(int param) {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int findSupportedParam(OssData * od, int param, int val) {
|
static int findSupportedParam(OssData * od, int param, int val)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
int index = getIndexForParam(param);
|
int index = getIndexForParam(param);
|
||||||
|
|
||||||
for(i = 0; i < od->numSupported[index]; i++) {
|
for (i = 0; i < od->numSupported[index]; i++) {
|
||||||
if(od->supported[index][i] == val) return 1;
|
if (od->supported[index][i] == val)
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int canConvert(int index, int val) {
|
static int canConvert(int index, int val)
|
||||||
switch(index) {
|
{
|
||||||
|
switch (index) {
|
||||||
case OSS_BITS:
|
case OSS_BITS:
|
||||||
if(val!=16) return 0;
|
if (val != 16)
|
||||||
|
return 0;
|
||||||
break;
|
break;
|
||||||
case OSS_CHANNELS:
|
case OSS_CHANNELS:
|
||||||
if(val!=2) return 0;
|
if (val != 2)
|
||||||
|
return 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getSupportedParam(OssData * od, int param, int val) {
|
static int getSupportedParam(OssData * od, int param, int val)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
int index = getIndexForParam(param);
|
int index = getIndexForParam(param);
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int least = val;
|
int least = val;
|
||||||
int diff;
|
int diff;
|
||||||
|
|
||||||
for(i = 0; i < od->numSupported[index]; i++) {
|
for (i = 0; i < od->numSupported[index]; i++) {
|
||||||
diff = od->supported[index][i]-val;
|
diff = od->supported[index][i] - val;
|
||||||
if(diff < 0) diff = -diff;
|
if (diff < 0)
|
||||||
if(diff < least) {
|
diff = -diff;
|
||||||
if(!canConvert(index, od->supported[index][i])) {
|
if (diff < least) {
|
||||||
|
if (!canConvert(index, od->supported[index][i])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
least = diff;
|
least = diff;
|
||||||
@ -137,97 +145,115 @@ static int getSupportedParam(OssData * od, int param, int val) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int findUnsupportedParam(OssData * od, int param, int val) {
|
static int findUnsupportedParam(OssData * od, int param, int val)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
int index = getIndexForParam(param);
|
int index = getIndexForParam(param);
|
||||||
|
|
||||||
for(i = 0; i < od->numUnsupported[index]; i++) {
|
for (i = 0; i < od->numUnsupported[index]; i++) {
|
||||||
if(od->unsupported[index][i] == val) return 1;
|
if (od->unsupported[index][i] == val)
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addSupportedParam(OssData * od, int param, int val) {
|
static void addSupportedParam(OssData * od, int param, int val)
|
||||||
|
{
|
||||||
int index = getIndexForParam(param);
|
int index = getIndexForParam(param);
|
||||||
|
|
||||||
od->numSupported[index]++;
|
od->numSupported[index]++;
|
||||||
od->supported[index] = realloc(od->supported[index],
|
od->supported[index] = realloc(od->supported[index],
|
||||||
od->numSupported[index]*sizeof(int));
|
od->numSupported[index] * sizeof(int));
|
||||||
od->supported[index][od->numSupported[index]-1] = val;
|
od->supported[index][od->numSupported[index] - 1] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addUnsupportedParam(OssData * od, int param, int val) {
|
static void addUnsupportedParam(OssData * od, int param, int val)
|
||||||
|
{
|
||||||
int index = getIndexForParam(param);
|
int index = getIndexForParam(param);
|
||||||
|
|
||||||
od->numUnsupported[index]++;
|
od->numUnsupported[index]++;
|
||||||
od->unsupported[index] = realloc(od->unsupported[index],
|
od->unsupported[index] = realloc(od->unsupported[index],
|
||||||
od->numUnsupported[index]*sizeof(int));
|
od->numUnsupported[index] *
|
||||||
od->unsupported[index][od->numUnsupported[index]-1] = val;
|
sizeof(int));
|
||||||
|
od->unsupported[index][od->numUnsupported[index] - 1] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void removeSupportedParam(OssData * od, int param, int val) {
|
static void removeSupportedParam(OssData * od, int param, int val)
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
int index = getIndexForParam(param);
|
int index = getIndexForParam(param);
|
||||||
|
|
||||||
for(i = 0; i < od->numSupported[index]-1; i++) {
|
for (i = 0; i < od->numSupported[index] - 1; i++) {
|
||||||
if(od->supported[index][i] == val) j = 1;
|
if (od->supported[index][i] == val)
|
||||||
od->supported[index][i] = od->supported[index][i+j];
|
j = 1;
|
||||||
|
od->supported[index][i] = od->supported[index][i + j];
|
||||||
}
|
}
|
||||||
|
|
||||||
od->numSupported[index]--;
|
od->numSupported[index]--;
|
||||||
od->supported[index] = realloc(od->supported[index],
|
od->supported[index] = realloc(od->supported[index],
|
||||||
od->numSupported[index]*sizeof(int));
|
od->numSupported[index] * sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void removeUnsupportedParam(OssData * od, int param, int val) {
|
static void removeUnsupportedParam(OssData * od, int param, int val)
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = 0;
|
int j = 0;
|
||||||
int index = getIndexForParam(param);
|
int index = getIndexForParam(param);
|
||||||
|
|
||||||
for(i = 0; i < od->numUnsupported[index]-1; i++) {
|
for (i = 0; i < od->numUnsupported[index] - 1; i++) {
|
||||||
if(od->unsupported[index][i] == val) j = 1;
|
if (od->unsupported[index][i] == val)
|
||||||
od->unsupported[index][i] = od->unsupported[index][i+j];
|
j = 1;
|
||||||
|
od->unsupported[index][i] = od->unsupported[index][i + j];
|
||||||
}
|
}
|
||||||
|
|
||||||
od->numUnsupported[index]--;
|
od->numUnsupported[index]--;
|
||||||
od->unsupported[index] = realloc(od->unsupported[index],
|
od->unsupported[index] = realloc(od->unsupported[index],
|
||||||
od->numUnsupported[index]*sizeof(int));
|
od->numUnsupported[index] *
|
||||||
|
sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int isSupportedParam(OssData * od, int param, int val) {
|
static int isSupportedParam(OssData * od, int param, int val)
|
||||||
if(findSupportedParam(od, param, val)) return OSS_SUPPORTED;
|
{
|
||||||
if(findUnsupportedParam(od, param, val)) return OSS_UNSUPPORTED;
|
if (findSupportedParam(od, param, val))
|
||||||
|
return OSS_SUPPORTED;
|
||||||
|
if (findUnsupportedParam(od, param, val))
|
||||||
|
return OSS_UNSUPPORTED;
|
||||||
return OSS_UNKNOWN;
|
return OSS_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void supportParam(OssData * od, int param, int val) {
|
static void supportParam(OssData * od, int param, int val)
|
||||||
|
{
|
||||||
int supported = isSupportedParam(od, param, val);
|
int supported = isSupportedParam(od, param, val);
|
||||||
|
|
||||||
if(supported == OSS_SUPPORTED) return;
|
if (supported == OSS_SUPPORTED)
|
||||||
|
return;
|
||||||
|
|
||||||
if(supported == OSS_UNSUPPORTED) {
|
if (supported == OSS_UNSUPPORTED) {
|
||||||
removeUnsupportedParam(od, param, val);
|
removeUnsupportedParam(od, param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
addSupportedParam(od, param, val);
|
addSupportedParam(od, param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unsupportParam(OssData * od, int param, int val) {
|
static void unsupportParam(OssData * od, int param, int val)
|
||||||
|
{
|
||||||
int supported = isSupportedParam(od, param, val);
|
int supported = isSupportedParam(od, param, val);
|
||||||
|
|
||||||
if(supported == OSS_UNSUPPORTED) return;
|
if (supported == OSS_UNSUPPORTED)
|
||||||
|
return;
|
||||||
|
|
||||||
if(supported == OSS_SUPPORTED) {
|
if (supported == OSS_SUPPORTED) {
|
||||||
removeSupportedParam(od, param, val);
|
removeSupportedParam(od, param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
addUnsupportedParam(od, param, val);
|
addUnsupportedParam(od, param, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static OssData * newOssData(void) {
|
static OssData *newOssData(void)
|
||||||
OssData * ret = malloc(sizeof(OssData));
|
{
|
||||||
|
OssData *ret = malloc(sizeof(OssData));
|
||||||
|
|
||||||
ret->device = NULL;
|
ret->device = NULL;
|
||||||
ret->fd = -1;
|
ret->fd = -1;
|
||||||
@ -254,15 +280,23 @@ static OssData * newOssData(void) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeOssData(OssData * od) {
|
static void freeOssData(OssData * od)
|
||||||
if(od->device) free(od->device);
|
{
|
||||||
|
if (od->device)
|
||||||
|
free(od->device);
|
||||||
|
|
||||||
if(od->supported[OSS_RATE]) free(od->supported[OSS_RATE]);
|
if (od->supported[OSS_RATE])
|
||||||
if(od->supported[OSS_CHANNELS]) free(od->supported[OSS_CHANNELS]);
|
free(od->supported[OSS_RATE]);
|
||||||
if(od->supported[OSS_BITS]) free(od->supported[OSS_BITS]);
|
if (od->supported[OSS_CHANNELS])
|
||||||
if(od->unsupported[OSS_RATE]) free(od->unsupported[OSS_RATE]);
|
free(od->supported[OSS_CHANNELS]);
|
||||||
if(od->unsupported[OSS_CHANNELS]) free(od->unsupported[OSS_CHANNELS]);
|
if (od->supported[OSS_BITS])
|
||||||
if(od->unsupported[OSS_BITS]) free(od->unsupported[OSS_BITS]);
|
free(od->supported[OSS_BITS]);
|
||||||
|
if (od->unsupported[OSS_RATE])
|
||||||
|
free(od->unsupported[OSS_RATE]);
|
||||||
|
if (od->unsupported[OSS_CHANNELS])
|
||||||
|
free(od->unsupported[OSS_CHANNELS]);
|
||||||
|
if (od->unsupported[OSS_BITS])
|
||||||
|
free(od->unsupported[OSS_BITS]);
|
||||||
|
|
||||||
free(od);
|
free(od);
|
||||||
}
|
}
|
||||||
@ -273,18 +307,18 @@ static void freeOssData(OssData * od) {
|
|||||||
#define OSS_STAT_DOESN_T_EXIST -3
|
#define OSS_STAT_DOESN_T_EXIST -3
|
||||||
#define OSS_STAT_OTHER -4
|
#define OSS_STAT_OTHER -4
|
||||||
|
|
||||||
static int oss_statDevice(char * device, int * stErrno) {
|
static int oss_statDevice(char *device, int *stErrno)
|
||||||
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if(0 == stat(device, &st)) {
|
if (0 == stat(device, &st)) {
|
||||||
if(!S_ISCHR(st.st_mode)) {
|
if (!S_ISCHR(st.st_mode)) {
|
||||||
return OSS_STAT_NOT_CHAR_DEV;
|
return OSS_STAT_NOT_CHAR_DEV;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
*stErrno = errno;
|
*stErrno = errno;
|
||||||
|
|
||||||
switch(errno) {
|
switch (errno) {
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
case ENOTDIR:
|
case ENOTDIR:
|
||||||
return OSS_STAT_DOESN_T_EXIST;
|
return OSS_STAT_DOESN_T_EXIST;
|
||||||
@ -298,12 +332,13 @@ static int oss_statDevice(char * device, int * stErrno) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oss_testDefault(void) {
|
static int oss_testDefault(void)
|
||||||
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
fd = open("/dev/sound/dsp", O_WRONLY);
|
fd = open("/dev/sound/dsp", O_WRONLY);
|
||||||
|
|
||||||
if(fd >= 0) {
|
if (fd >= 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -313,108 +348,106 @@ static int oss_testDefault(void) {
|
|||||||
|
|
||||||
fd = open("/dev/dsp", O_WRONLY);
|
fd = open("/dev/dsp", O_WRONLY);
|
||||||
|
|
||||||
if(fd >= 0) {
|
if (fd >= 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
WARNING("Error opening OSS device \"/dev/dsp\": %s\n",
|
WARNING("Error opening OSS device \"/dev/dsp\": %s\n", strerror(errno));
|
||||||
strerror(errno));
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oss_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
static int oss_initDriver(AudioOutput * audioOutput, ConfigParam * param)
|
||||||
BlockParam * bp = NULL;
|
{
|
||||||
OssData * od;
|
BlockParam *bp = NULL;
|
||||||
|
OssData *od;
|
||||||
|
|
||||||
if(param) bp = getBlockParam(param, "device");
|
if (param)
|
||||||
|
bp = getBlockParam(param, "device");
|
||||||
|
|
||||||
od = newOssData();
|
od = newOssData();
|
||||||
audioOutput->data = od;
|
audioOutput->data = od;
|
||||||
|
|
||||||
if(!bp) {
|
if (!bp) {
|
||||||
int err[2];
|
int err[2];
|
||||||
int ret[2];
|
int ret[2];
|
||||||
|
|
||||||
ret[0] = oss_statDevice("/dev/sound/dsp", err);
|
ret[0] = oss_statDevice("/dev/sound/dsp", err);
|
||||||
ret[1] = oss_statDevice("/dev/dsp", err+1);
|
ret[1] = oss_statDevice("/dev/dsp", err + 1);
|
||||||
|
|
||||||
if(ret[0] == 0) od->device = strdup("/dev/sound/dsp");
|
if (ret[0] == 0)
|
||||||
else if(ret[1] == 0) od->device = strdup("/dev/dsp");
|
od->device = strdup("/dev/sound/dsp");
|
||||||
|
else if (ret[1] == 0)
|
||||||
|
od->device = strdup("/dev/dsp");
|
||||||
else {
|
else {
|
||||||
if(param) {
|
if (param) {
|
||||||
ERROR("Error trying to open default OSS device "
|
ERROR("Error trying to open default OSS device "
|
||||||
"specified at line %i\n", param->line);
|
"specified at line %i\n", param->line);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ERROR("Error trying to open default OSS "
|
ERROR("Error trying to open default OSS "
|
||||||
"device\n");
|
"device\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if((ret[0] == OSS_STAT_DOESN_T_EXIST) &&
|
if ((ret[0] == OSS_STAT_DOESN_T_EXIST) &&
|
||||||
(ret[1] == OSS_STAT_DOESN_T_EXIST)) {
|
(ret[1] == OSS_STAT_DOESN_T_EXIST)) {
|
||||||
ERROR("Neither /dev/dsp nor /dev/sound/dsp "
|
ERROR("Neither /dev/dsp nor /dev/sound/dsp "
|
||||||
"were found\n");
|
"were found\n");
|
||||||
}
|
} else if (ret[0] == OSS_STAT_NOT_CHAR_DEV) {
|
||||||
else if(ret[0] == OSS_STAT_NOT_CHAR_DEV) {
|
|
||||||
ERROR("/dev/sound/dsp is not a char device");
|
ERROR("/dev/sound/dsp is not a char device");
|
||||||
}
|
} else if (ret[1] == OSS_STAT_NOT_CHAR_DEV) {
|
||||||
else if(ret[1] == OSS_STAT_NOT_CHAR_DEV) {
|
|
||||||
ERROR("/dev/dsp is not a char device");
|
ERROR("/dev/dsp is not a char device");
|
||||||
}
|
} else if (ret[0] == OSS_STAT_NO_PERMS) {
|
||||||
else if(ret[0] == OSS_STAT_NO_PERMS) {
|
|
||||||
ERROR("no permission to access /dev/sound/dsp");
|
ERROR("no permission to access /dev/sound/dsp");
|
||||||
}
|
} else if (ret[1] == OSS_STAT_NO_PERMS) {
|
||||||
else if(ret[1] == OSS_STAT_NO_PERMS) {
|
|
||||||
ERROR("no permission to access /dev/dsp");
|
ERROR("no permission to access /dev/dsp");
|
||||||
}
|
} else if (ret[0] == OSS_STAT_OTHER) {
|
||||||
else if(ret[0] == OSS_STAT_OTHER) {
|
|
||||||
ERROR("Error accessing /dev/sound/dsp: %s",
|
ERROR("Error accessing /dev/sound/dsp: %s",
|
||||||
strerror(err[0]));
|
strerror(err[0]));
|
||||||
}
|
} else if (ret[1] == OSS_STAT_OTHER) {
|
||||||
else if(ret[1] == OSS_STAT_OTHER) {
|
|
||||||
ERROR("Error accessing /dev/dsp: %s",
|
ERROR("Error accessing /dev/dsp: %s",
|
||||||
strerror(err[1]));
|
strerror(err[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else od->device = strdup(bp->value);
|
od->device = strdup(bp->value);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void oss_finishDriver(AudioOutput * audioOutput) {
|
static void oss_finishDriver(AudioOutput * audioOutput)
|
||||||
OssData * od = audioOutput->data;
|
{
|
||||||
|
OssData *od = audioOutput->data;
|
||||||
|
|
||||||
freeOssData(od);
|
freeOssData(od);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int setParam(OssData * od, int param, int * value) {
|
static int setParam(OssData * od, int param, int *value)
|
||||||
|
{
|
||||||
int val = *value;
|
int val = *value;
|
||||||
int copy;
|
int copy;
|
||||||
int supported = isSupportedParam(od, param, val);
|
int supported = isSupportedParam(od, param, val);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(supported == OSS_UNSUPPORTED) {
|
if (supported == OSS_UNSUPPORTED) {
|
||||||
val = getSupportedParam(od, param, val);
|
val = getSupportedParam(od, param, val);
|
||||||
if(copy < 0) return -1;
|
if (copy < 0)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
copy = val;
|
copy = val;
|
||||||
if(ioctl(od->fd, param, ©)) {
|
if (ioctl(od->fd, param, ©)) {
|
||||||
unsupportParam(od, param, val);
|
unsupportParam(od, param, val);
|
||||||
supported = OSS_UNSUPPORTED;
|
supported = OSS_UNSUPPORTED;
|
||||||
}
|
} else {
|
||||||
else {
|
if (supported == OSS_UNKNOWN) {
|
||||||
if(supported == OSS_UNKNOWN) {
|
|
||||||
supportParam(od, param, val);
|
supportParam(od, param, val);
|
||||||
supported = OSS_SUPPORTED;
|
supported = OSS_SUPPORTED;
|
||||||
}
|
}
|
||||||
val = copy;
|
val = copy;
|
||||||
}
|
}
|
||||||
} while( supported == OSS_UNSUPPORTED );
|
} while (supported == OSS_UNSUPPORTED);
|
||||||
|
|
||||||
*value = val;
|
*value = val;
|
||||||
|
|
||||||
@ -423,37 +456,35 @@ static int setParam(OssData * od, int param, int * value) {
|
|||||||
|
|
||||||
static void oss_close(OssData * od)
|
static void oss_close(OssData * od)
|
||||||
{
|
{
|
||||||
if(od->fd >= 0) while (close(od->fd) && errno == EINTR);
|
if (od->fd >= 0)
|
||||||
|
while (close(od->fd) && errno == EINTR) ;
|
||||||
od->fd = -1;
|
od->fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oss_open(AudioOutput * audioOutput) {
|
static int oss_open(AudioOutput * audioOutput)
|
||||||
|
{
|
||||||
int tmp;
|
int tmp;
|
||||||
OssData * od = audioOutput->data;
|
OssData *od = audioOutput->data;
|
||||||
|
|
||||||
if((od->fd = open(od->device, O_WRONLY)) < 0) {
|
if ((od->fd = open(od->device, O_WRONLY)) < 0) {
|
||||||
ERROR("Error opening OSS device \"%s\": %s\n", od->device,
|
ERROR("Error opening OSS device \"%s\": %s\n", od->device,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(setParam(od, SNDCTL_DSP_CHANNELS, &od->channels)) {
|
if (setParam(od, SNDCTL_DSP_CHANNELS, &od->channels)) {
|
||||||
ERROR("OSS device \"%s\" does not support %i channels: %s\n",
|
ERROR("OSS device \"%s\" does not support %i channels: %s\n",
|
||||||
od->device,
|
od->device, od->channels, strerror(errno));
|
||||||
od->channels,
|
|
||||||
strerror(errno));
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(setParam(od, SNDCTL_DSP_SPEED, &od->sampleRate)) {
|
if (setParam(od, SNDCTL_DSP_SPEED, &od->sampleRate)) {
|
||||||
ERROR("OSS device \"%s\" does not support %i Hz audio: %s\n",
|
ERROR("OSS device \"%s\" does not support %i Hz audio: %s\n",
|
||||||
od->device,
|
od->device, od->sampleRate, strerror(errno));
|
||||||
od->sampleRate,
|
|
||||||
strerror(errno));
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(od->bits) {
|
switch (od->bits) {
|
||||||
case 8:
|
case 8:
|
||||||
tmp = AFMT_S8;
|
tmp = AFMT_S8;
|
||||||
break;
|
break;
|
||||||
@ -461,11 +492,9 @@ static int oss_open(AudioOutput * audioOutput) {
|
|||||||
tmp = AFMT_S16_MPD;
|
tmp = AFMT_S16_MPD;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(setParam(od, SNDCTL_DSP_SAMPLESIZE, &tmp)) {
|
if (setParam(od, SNDCTL_DSP_SAMPLESIZE, &tmp)) {
|
||||||
ERROR("OSS device \"%s\" does not support %i bit audio: %s\n",
|
ERROR("OSS device \"%s\" does not support %i bit audio: %s\n",
|
||||||
od->device,
|
od->device, tmp, strerror(errno));
|
||||||
tmp,
|
|
||||||
strerror(errno));
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +502,7 @@ static int oss_open(AudioOutput * audioOutput) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
oss_close(od);
|
oss_close(od);
|
||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
return -1;
|
return -1;
|
||||||
@ -482,8 +511,8 @@ fail:
|
|||||||
static int oss_openDevice(AudioOutput * audioOutput)
|
static int oss_openDevice(AudioOutput * audioOutput)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
OssData * od = audioOutput->data;
|
OssData *od = audioOutput->data;
|
||||||
AudioFormat * audioFormat = &audioOutput->outAudioFormat;
|
AudioFormat *audioFormat = &audioOutput->outAudioFormat;
|
||||||
|
|
||||||
od->channels = audioFormat->channels;
|
od->channels = audioFormat->channels;
|
||||||
od->sampleRate = audioFormat->sampleRate;
|
od->sampleRate = audioFormat->sampleRate;
|
||||||
@ -497,43 +526,44 @@ static int oss_openDevice(AudioOutput * audioOutput)
|
|||||||
audioFormat->bits = od->bits;
|
audioFormat->bits = od->bits;
|
||||||
|
|
||||||
DEBUG("oss device \"%s\" will be playing %i bit %i channel audio at "
|
DEBUG("oss device \"%s\" will be playing %i bit %i channel audio at "
|
||||||
"%i Hz\n", od->device, od->bits,
|
"%i Hz\n", od->device, od->bits, od->channels, od->sampleRate);
|
||||||
od->channels, od->sampleRate);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void oss_closeDevice(AudioOutput * audioOutput) {
|
static void oss_closeDevice(AudioOutput * audioOutput)
|
||||||
OssData * od = audioOutput->data;
|
{
|
||||||
|
OssData *od = audioOutput->data;
|
||||||
|
|
||||||
oss_close(od);
|
oss_close(od);
|
||||||
|
|
||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void oss_dropBufferedAudio(AudioOutput * audioOutput) {
|
static void oss_dropBufferedAudio(AudioOutput * audioOutput)
|
||||||
OssData * od = audioOutput->data;
|
{
|
||||||
|
OssData *od = audioOutput->data;
|
||||||
|
|
||||||
if(od->fd >= 0) {
|
if (od->fd >= 0) {
|
||||||
ioctl(od->fd, SNDCTL_DSP_RESET, 0);
|
ioctl(od->fd, SNDCTL_DSP_RESET, 0);
|
||||||
oss_close(od);
|
oss_close(od);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oss_playAudio(AudioOutput * audioOutput, char * playChunk,
|
static int oss_playAudio(AudioOutput * audioOutput, char *playChunk, int size)
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
OssData * od = audioOutput->data;
|
OssData *od = audioOutput->data;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* reopen the device since it was closed by dropBufferedAudio */
|
/* reopen the device since it was closed by dropBufferedAudio */
|
||||||
if(od->fd < 0 && oss_open(audioOutput) < 0)
|
if (od->fd < 0 && oss_open(audioOutput) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
while (size > 0) {
|
while (size > 0) {
|
||||||
ret = write(od->fd, playChunk, size);
|
ret = write(od->fd, playChunk, size);
|
||||||
if(ret<0) {
|
if (ret < 0) {
|
||||||
if(errno == EINTR) continue;
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
ERROR("closing oss device \"%s\" due to write error: "
|
ERROR("closing oss device \"%s\" due to write error: "
|
||||||
"%s\n", od->device, strerror(errno));
|
"%s\n", od->device, strerror(errno));
|
||||||
oss_closeDevice(audioOutput);
|
oss_closeDevice(audioOutput);
|
||||||
@ -546,8 +576,7 @@ static int oss_playAudio(AudioOutput * audioOutput, char * playChunk,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioOutputPlugin ossPlugin =
|
AudioOutputPlugin ossPlugin = {
|
||||||
{
|
|
||||||
"oss",
|
"oss",
|
||||||
oss_testDefault,
|
oss_testDefault,
|
||||||
oss_initDriver,
|
oss_initDriver,
|
||||||
@ -562,5 +591,4 @@ AudioOutputPlugin ossPlugin =
|
|||||||
#else /* HAVE OSS */
|
#else /* HAVE OSS */
|
||||||
|
|
||||||
DISABLED_AUDIO_OUTPUT_PLUGIN(ossPlugin)
|
DISABLED_AUDIO_OUTPUT_PLUGIN(ossPlugin)
|
||||||
|
|
||||||
#endif /* HAVE_OSS */
|
#endif /* HAVE_OSS */
|
||||||
|
@ -31,15 +31,16 @@ typedef struct _OsxData {
|
|||||||
AudioUnit au;
|
AudioUnit au;
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
pthread_cond_t condition;
|
pthread_cond_t condition;
|
||||||
char * buffer;
|
char *buffer;
|
||||||
int bufferSize;
|
int bufferSize;
|
||||||
int pos;
|
int pos;
|
||||||
int len;
|
int len;
|
||||||
int started;
|
int started;
|
||||||
} OsxData;
|
} OsxData;
|
||||||
|
|
||||||
static OsxData * newOsxData() {
|
static OsxData *newOsxData()
|
||||||
OsxData * ret = malloc(sizeof(OsxData));
|
{
|
||||||
|
OsxData *ret = malloc(sizeof(OsxData));
|
||||||
|
|
||||||
pthread_mutex_init(&ret->mutex, NULL);
|
pthread_mutex_init(&ret->mutex, NULL);
|
||||||
pthread_cond_init(&ret->condition, NULL);
|
pthread_cond_init(&ret->condition, NULL);
|
||||||
@ -53,7 +54,8 @@ static OsxData * newOsxData() {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int osx_testDefault() {
|
static int osx_testDefault()
|
||||||
|
{
|
||||||
/*AudioUnit au;
|
/*AudioUnit au;
|
||||||
ComponentDescription desc;
|
ComponentDescription desc;
|
||||||
Component comp;
|
Component comp;
|
||||||
@ -75,49 +77,55 @@ static int osx_testDefault() {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CloseComponent(au);*/
|
CloseComponent(au); */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int osx_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
static int osx_initDriver(AudioOutput * audioOutput, ConfigParam * param)
|
||||||
OsxData * od = newOsxData();
|
{
|
||||||
|
OsxData *od = newOsxData();
|
||||||
|
|
||||||
audioOutput->data = od;
|
audioOutput->data = od;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeOsxData(OsxData * od) {
|
static void freeOsxData(OsxData * od)
|
||||||
if(od->buffer) free(od->buffer);
|
{
|
||||||
|
if (od->buffer)
|
||||||
|
free(od->buffer);
|
||||||
pthread_mutex_destroy(&od->mutex);
|
pthread_mutex_destroy(&od->mutex);
|
||||||
pthread_cond_destroy(&od->condition);
|
pthread_cond_destroy(&od->condition);
|
||||||
free(od);
|
free(od);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void osx_finishDriver(AudioOutput * audioOutput) {
|
static void osx_finishDriver(AudioOutput * audioOutput)
|
||||||
OsxData * od = (OsxData *)audioOutput->data;
|
{
|
||||||
|
OsxData *od = (OsxData *) audioOutput->data;
|
||||||
freeOsxData(od);
|
freeOsxData(od);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void osx_dropBufferedAudio(AudioOutput * audioOutput) {
|
static void osx_dropBufferedAudio(AudioOutput * audioOutput)
|
||||||
OsxData * od = (OsxData *)audioOutput->data;
|
{
|
||||||
|
OsxData *od = (OsxData *) audioOutput->data;
|
||||||
|
|
||||||
pthread_mutex_lock(&od->mutex);
|
pthread_mutex_lock(&od->mutex);
|
||||||
od->len = 0;
|
od->len = 0;
|
||||||
pthread_mutex_unlock(&od->mutex);
|
pthread_mutex_unlock(&od->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void osx_closeDevice(AudioOutput * audioOutput) {
|
static void osx_closeDevice(AudioOutput * audioOutput)
|
||||||
OsxData * od = (OsxData *) audioOutput->data;
|
{
|
||||||
|
OsxData *od = (OsxData *) audioOutput->data;
|
||||||
|
|
||||||
pthread_mutex_lock(&od->mutex);
|
pthread_mutex_lock(&od->mutex);
|
||||||
while(od->len) {
|
while (od->len) {
|
||||||
pthread_cond_wait(&od->condition, &od->mutex);
|
pthread_cond_wait(&od->condition, &od->mutex);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&od->mutex);
|
pthread_mutex_unlock(&od->mutex);
|
||||||
|
|
||||||
if(od->started) {
|
if (od->started) {
|
||||||
AudioOutputUnitStop(od->au);
|
AudioOutputUnitStop(od->au);
|
||||||
od->started = 0;
|
od->started = 0;
|
||||||
}
|
}
|
||||||
@ -128,14 +136,14 @@ static void osx_closeDevice(AudioOutput * audioOutput) {
|
|||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus osx_render(void * vdata,
|
static OSStatus osx_render(void *vdata,
|
||||||
AudioUnitRenderActionFlags *ioActionFlags,
|
AudioUnitRenderActionFlags * ioActionFlags,
|
||||||
const AudioTimeStamp * inTimeStamp,
|
const AudioTimeStamp * inTimeStamp,
|
||||||
UInt32 inBusNumber, UInt32 inNumberFrames,
|
UInt32 inBusNumber, UInt32 inNumberFrames,
|
||||||
AudioBufferList *bufferList)
|
AudioBufferList * bufferList)
|
||||||
{
|
{
|
||||||
OsxData * od = (OsxData *)vdata;
|
OsxData *od = (OsxData *) vdata;
|
||||||
AudioBuffer * buffer = &bufferList->mBuffers[0];
|
AudioBuffer *buffer = &bufferList->mBuffers[0];
|
||||||
int bufferSize = buffer->mDataByteSize;
|
int bufferSize = buffer->mDataByteSize;
|
||||||
int bytesToCopy;
|
int bytesToCopy;
|
||||||
int curpos = 0;
|
int curpos = 0;
|
||||||
@ -161,7 +169,7 @@ static OSStatus osx_render(void * vdata,
|
|||||||
if(*ioActionFlags & kAudioOfflineUnitRenderAction_Complete) {
|
if(*ioActionFlags & kAudioOfflineUnitRenderAction_Complete) {
|
||||||
DEBUG("complete\n");
|
DEBUG("complete\n");
|
||||||
}
|
}
|
||||||
}*/
|
} */
|
||||||
|
|
||||||
/* while(bufferSize) {
|
/* while(bufferSize) {
|
||||||
DEBUG("osx_render: lock\n"); */
|
DEBUG("osx_render: lock\n"); */
|
||||||
@ -180,19 +188,20 @@ static OSStatus osx_render(void * vdata,
|
|||||||
bufferSize = bytesToCopy;
|
bufferSize = bytesToCopy;
|
||||||
od->len -= bytesToCopy;
|
od->len -= bytesToCopy;
|
||||||
|
|
||||||
if(od->pos+bytesToCopy > od->bufferSize) {
|
if (od->pos + bytesToCopy > od->bufferSize) {
|
||||||
int bytes = od->bufferSize-od->pos;
|
int bytes = od->bufferSize - od->pos;
|
||||||
memcpy(buffer->mData+curpos, od->buffer+od->pos, bytes);
|
memcpy(buffer->mData + curpos, od->buffer + od->pos, bytes);
|
||||||
od->pos = 0;
|
od->pos = 0;
|
||||||
curpos += bytes;
|
curpos += bytes;
|
||||||
bytesToCopy -= bytes;
|
bytesToCopy -= bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(buffer->mData+curpos, od->buffer+od->pos, bytesToCopy);
|
memcpy(buffer->mData + curpos, od->buffer + od->pos, bytesToCopy);
|
||||||
od->pos += bytesToCopy;
|
od->pos += bytesToCopy;
|
||||||
curpos += bytesToCopy;
|
curpos += bytesToCopy;
|
||||||
|
|
||||||
if(od->pos >= od->bufferSize) od->pos = 0;
|
if (od->pos >= od->bufferSize)
|
||||||
|
od->pos = 0;
|
||||||
/* DEBUG("osx_render: unlock\n"); */
|
/* DEBUG("osx_render: unlock\n"); */
|
||||||
pthread_mutex_unlock(&od->mutex);
|
pthread_mutex_unlock(&od->mutex);
|
||||||
pthread_cond_signal(&od->condition);
|
pthread_cond_signal(&od->condition);
|
||||||
@ -200,7 +209,7 @@ static OSStatus osx_render(void * vdata,
|
|||||||
|
|
||||||
buffer->mDataByteSize = bufferSize;
|
buffer->mDataByteSize = bufferSize;
|
||||||
|
|
||||||
if(!bufferSize) {
|
if (!bufferSize) {
|
||||||
my_usleep(1000);
|
my_usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,12 +217,13 @@ static OSStatus osx_render(void * vdata,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int osx_openDevice(AudioOutput * audioOutput) {
|
static int osx_openDevice(AudioOutput * audioOutput)
|
||||||
OsxData * od = (OsxData *)audioOutput->data;
|
{
|
||||||
|
OsxData *od = (OsxData *) audioOutput->data;
|
||||||
ComponentDescription desc;
|
ComponentDescription desc;
|
||||||
Component comp;
|
Component comp;
|
||||||
AURenderCallbackStruct callback;
|
AURenderCallbackStruct callback;
|
||||||
AudioFormat * audioFormat = &audioOutput->outAudioFormat;
|
AudioFormat *audioFormat = &audioOutput->outAudioFormat;
|
||||||
AudioStreamBasicDescription streamDesc;
|
AudioStreamBasicDescription streamDesc;
|
||||||
|
|
||||||
desc.componentType = kAudioUnitType_Output;
|
desc.componentType = kAudioUnitType_Output;
|
||||||
@ -223,17 +233,17 @@ static int osx_openDevice(AudioOutput * audioOutput) {
|
|||||||
desc.componentFlagsMask = 0;
|
desc.componentFlagsMask = 0;
|
||||||
|
|
||||||
comp = FindNextComponent(NULL, &desc);
|
comp = FindNextComponent(NULL, &desc);
|
||||||
if(comp == 0) {
|
if (comp == 0) {
|
||||||
ERROR("Error finding OS X component\n");
|
ERROR("Error finding OS X component\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(OpenAComponent(comp, &od->au) != noErr) {
|
if (OpenAComponent(comp, &od->au) != noErr) {
|
||||||
ERROR("Unable to open OS X component\n");
|
ERROR("Unable to open OS X component\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(AudioUnitInitialize(od->au) != 0) {
|
if (AudioUnitInitialize(od->au) != 0) {
|
||||||
CloseComponent(od->au);
|
CloseComponent(od->au);
|
||||||
ERROR("Unable to initialuze OS X audio unit\n");
|
ERROR("Unable to initialuze OS X audio unit\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -242,10 +252,9 @@ static int osx_openDevice(AudioOutput * audioOutput) {
|
|||||||
callback.inputProc = osx_render;
|
callback.inputProc = osx_render;
|
||||||
callback.inputProcRefCon = od;
|
callback.inputProcRefCon = od;
|
||||||
|
|
||||||
if(AudioUnitSetProperty(od->au, kAudioUnitProperty_SetRenderCallback,
|
if (AudioUnitSetProperty(od->au, kAudioUnitProperty_SetRenderCallback,
|
||||||
kAudioUnitScope_Input, 0,
|
kAudioUnitScope_Input, 0,
|
||||||
&callback, sizeof(callback)) != 0)
|
&callback, sizeof(callback)) != 0) {
|
||||||
{
|
|
||||||
AudioUnitUninitialize(od->au);
|
AudioUnitUninitialize(od->au);
|
||||||
CloseComponent(od->au);
|
CloseComponent(od->au);
|
||||||
ERROR("unable to set callbak for OS X audio unit\n");
|
ERROR("unable to set callbak for OS X audio unit\n");
|
||||||
@ -256,16 +265,16 @@ static int osx_openDevice(AudioOutput * audioOutput) {
|
|||||||
streamDesc.mFormatID = kAudioFormatLinearPCM;
|
streamDesc.mFormatID = kAudioFormatLinearPCM;
|
||||||
streamDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger |
|
streamDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger |
|
||||||
kLinearPCMFormatFlagIsBigEndian;
|
kLinearPCMFormatFlagIsBigEndian;
|
||||||
streamDesc.mBytesPerPacket = audioFormat->channels*audioFormat->bits/8;
|
streamDesc.mBytesPerPacket =
|
||||||
|
audioFormat->channels * audioFormat->bits / 8;
|
||||||
streamDesc.mFramesPerPacket = 1;
|
streamDesc.mFramesPerPacket = 1;
|
||||||
streamDesc.mBytesPerFrame = streamDesc.mBytesPerPacket;
|
streamDesc.mBytesPerFrame = streamDesc.mBytesPerPacket;
|
||||||
streamDesc.mChannelsPerFrame = audioFormat->channels;
|
streamDesc.mChannelsPerFrame = audioFormat->channels;
|
||||||
streamDesc.mBitsPerChannel = audioFormat->bits;
|
streamDesc.mBitsPerChannel = audioFormat->bits;
|
||||||
|
|
||||||
if(AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
|
if (AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
|
||||||
kAudioUnitScope_Input, 0,
|
kAudioUnitScope_Input, 0,
|
||||||
&streamDesc, sizeof(streamDesc)) != 0)
|
&streamDesc, sizeof(streamDesc)) != 0) {
|
||||||
{
|
|
||||||
AudioUnitUninitialize(od->au);
|
AudioUnitUninitialize(od->au);
|
||||||
CloseComponent(od->au);
|
CloseComponent(od->au);
|
||||||
ERROR("Unable to set format on OS X device\n");
|
ERROR("Unable to set format on OS X device\n");
|
||||||
@ -285,18 +294,19 @@ static int osx_openDevice(AudioOutput * audioOutput) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int osx_play(AudioOutput * audioOutput, char * playChunk, int size) {
|
static int osx_play(AudioOutput * audioOutput, char *playChunk, int size)
|
||||||
OsxData * od = (OsxData *)audioOutput->data;
|
{
|
||||||
|
OsxData *od = (OsxData *) audioOutput->data;
|
||||||
int bytesToCopy;
|
int bytesToCopy;
|
||||||
int curpos;
|
int curpos;
|
||||||
|
|
||||||
/* DEBUG("osx_play: enter\n"); */
|
/* DEBUG("osx_play: enter\n"); */
|
||||||
|
|
||||||
if(!od->started) {
|
if (!od->started) {
|
||||||
int err;
|
int err;
|
||||||
od->started = 1;
|
od->started = 1;
|
||||||
err = AudioOutputUnitStart(od->au);
|
err = AudioOutputUnitStart(od->au);
|
||||||
if(err) {
|
if (err) {
|
||||||
ERROR("unable to start audio output: %i\n", err);
|
ERROR("unable to start audio output: %i\n", err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -304,14 +314,15 @@ static int osx_play(AudioOutput * audioOutput, char * playChunk, int size) {
|
|||||||
|
|
||||||
pthread_mutex_lock(&od->mutex);
|
pthread_mutex_lock(&od->mutex);
|
||||||
|
|
||||||
while(size) {
|
while (size) {
|
||||||
/* DEBUG("osx_play: lock\n"); */
|
/* DEBUG("osx_play: lock\n"); */
|
||||||
curpos = od->pos+od->len;
|
curpos = od->pos + od->len;
|
||||||
if(curpos >= od->bufferSize) curpos -= od->bufferSize;
|
if (curpos >= od->bufferSize)
|
||||||
|
curpos -= od->bufferSize;
|
||||||
|
|
||||||
bytesToCopy = od->bufferSize < size ? od->bufferSize : size;
|
bytesToCopy = od->bufferSize < size ? od->bufferSize : size;
|
||||||
|
|
||||||
while(od->len > od->bufferSize-bytesToCopy) {
|
while (od->len > od->bufferSize - bytesToCopy) {
|
||||||
/* DEBUG("osx_play: wait\n"); */
|
/* DEBUG("osx_play: wait\n"); */
|
||||||
pthread_cond_wait(&od->condition, &od->mutex);
|
pthread_cond_wait(&od->condition, &od->mutex);
|
||||||
}
|
}
|
||||||
@ -321,15 +332,15 @@ static int osx_play(AudioOutput * audioOutput, char * playChunk, int size) {
|
|||||||
size -= bytesToCopy;
|
size -= bytesToCopy;
|
||||||
od->len += bytesToCopy;
|
od->len += bytesToCopy;
|
||||||
|
|
||||||
if(curpos+bytesToCopy > od->bufferSize) {
|
if (curpos + bytesToCopy > od->bufferSize) {
|
||||||
int bytes = od->bufferSize-curpos;
|
int bytes = od->bufferSize - curpos;
|
||||||
memcpy(od->buffer+curpos, playChunk, bytes);
|
memcpy(od->buffer + curpos, playChunk, bytes);
|
||||||
curpos = 0;
|
curpos = 0;
|
||||||
playChunk += bytes;
|
playChunk += bytes;
|
||||||
bytesToCopy -= bytes;
|
bytesToCopy -= bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(od->buffer+curpos, playChunk, bytesToCopy);
|
memcpy(od->buffer + curpos, playChunk, bytesToCopy);
|
||||||
curpos += bytesToCopy;
|
curpos += bytesToCopy;
|
||||||
playChunk += bytesToCopy;
|
playChunk += bytesToCopy;
|
||||||
|
|
||||||
@ -341,8 +352,7 @@ static int osx_play(AudioOutput * audioOutput, char * playChunk, int size) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioOutputPlugin osxPlugin =
|
AudioOutputPlugin osxPlugin = {
|
||||||
{
|
|
||||||
"osx",
|
"osx",
|
||||||
osx_testDefault,
|
osx_testDefault,
|
||||||
osx_initDriver,
|
osx_initDriver,
|
||||||
@ -359,5 +369,4 @@ AudioOutputPlugin osxPlugin =
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
DISABLED_AUDIO_OUTPUT_PLUGIN(osxPlugin)
|
DISABLED_AUDIO_OUTPUT_PLUGIN(osxPlugin)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,16 +34,16 @@
|
|||||||
#define CONN_ATTEMPT_INTERVAL 60
|
#define CONN_ATTEMPT_INTERVAL 60
|
||||||
|
|
||||||
typedef struct _PulseData {
|
typedef struct _PulseData {
|
||||||
pa_simple * s;
|
pa_simple *s;
|
||||||
char * server;
|
char *server;
|
||||||
char * sink;
|
char *sink;
|
||||||
int connAttempts;
|
int connAttempts;
|
||||||
time_t lastAttempt;
|
time_t lastAttempt;
|
||||||
} PulseData;
|
} PulseData;
|
||||||
|
|
||||||
static PulseData * newPulseData()
|
static PulseData *newPulseData()
|
||||||
{
|
{
|
||||||
PulseData * ret;
|
PulseData *ret;
|
||||||
|
|
||||||
ret = malloc(sizeof(PulseData));
|
ret = malloc(sizeof(PulseData));
|
||||||
|
|
||||||
@ -58,16 +58,18 @@ static PulseData * newPulseData()
|
|||||||
|
|
||||||
static void freePulseData(PulseData * pd)
|
static void freePulseData(PulseData * pd)
|
||||||
{
|
{
|
||||||
if (pd->server) free(pd->server);
|
if (pd->server)
|
||||||
if (pd->sink) free(pd->sink);
|
free(pd->server);
|
||||||
|
if (pd->sink)
|
||||||
|
free(pd->sink);
|
||||||
free(pd);
|
free(pd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pulse_initDriver(AudioOutput * audioOutput, ConfigParam * param)
|
static int pulse_initDriver(AudioOutput * audioOutput, ConfigParam * param)
|
||||||
{
|
{
|
||||||
BlockParam * server = NULL;
|
BlockParam *server = NULL;
|
||||||
BlockParam * sink = NULL;
|
BlockParam *sink = NULL;
|
||||||
PulseData * pd;
|
PulseData *pd;
|
||||||
|
|
||||||
if (param) {
|
if (param) {
|
||||||
server = getBlockParam(param, "server");
|
server = getBlockParam(param, "server");
|
||||||
@ -89,7 +91,7 @@ static void pulse_finishDriver(AudioOutput * audioOutput)
|
|||||||
|
|
||||||
static int pulse_testDefault()
|
static int pulse_testDefault()
|
||||||
{
|
{
|
||||||
pa_simple * s;
|
pa_simple *s;
|
||||||
pa_sample_spec ss;
|
pa_sample_spec ss;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -112,8 +114,8 @@ static int pulse_testDefault()
|
|||||||
|
|
||||||
static int pulse_openDevice(AudioOutput * audioOutput)
|
static int pulse_openDevice(AudioOutput * audioOutput)
|
||||||
{
|
{
|
||||||
PulseData * pd;
|
PulseData *pd;
|
||||||
AudioFormat * audioFormat;
|
AudioFormat *audioFormat;
|
||||||
pa_sample_spec ss;
|
pa_sample_spec ss;
|
||||||
time_t t;
|
time_t t;
|
||||||
int error;
|
int error;
|
||||||
@ -123,7 +125,8 @@ static int pulse_openDevice(AudioOutput * audioOutput)
|
|||||||
audioFormat = &audioOutput->outAudioFormat;
|
audioFormat = &audioOutput->outAudioFormat;
|
||||||
|
|
||||||
if (pd->connAttempts != 0 &&
|
if (pd->connAttempts != 0 &&
|
||||||
(t - pd->lastAttempt) < CONN_ATTEMPT_INTERVAL) return -1;
|
(t - pd->lastAttempt) < CONN_ATTEMPT_INTERVAL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
pd->connAttempts++;
|
pd->connAttempts++;
|
||||||
pd->lastAttempt = t;
|
pd->lastAttempt = t;
|
||||||
@ -142,7 +145,7 @@ static int pulse_openDevice(AudioOutput * audioOutput)
|
|||||||
pd->sink, audioOutput->name, &ss, NULL, NULL,
|
pd->sink, audioOutput->name, &ss, NULL, NULL,
|
||||||
&error);
|
&error);
|
||||||
if (!pd->s) {
|
if (!pd->s) {
|
||||||
ERROR("Cannot connect to server in PulseAudio output " \
|
ERROR("Cannot connect to server in PulseAudio output "
|
||||||
"\"%s\" (attempt %i): %s\n", audioOutput->name,
|
"\"%s\" (attempt %i): %s\n", audioOutput->name,
|
||||||
pd->connAttempts, pa_strerror(error));
|
pd->connAttempts, pa_strerror(error));
|
||||||
return -1;
|
return -1;
|
||||||
@ -151,7 +154,7 @@ static int pulse_openDevice(AudioOutput * audioOutput)
|
|||||||
pd->connAttempts = 0;
|
pd->connAttempts = 0;
|
||||||
audioOutput->open = 1;
|
audioOutput->open = 1;
|
||||||
|
|
||||||
DEBUG("PulseAudio output \"%s\" connected and playing %i bit, %i " \
|
DEBUG("PulseAudio output \"%s\" connected and playing %i bit, %i "
|
||||||
"channel audio at %i Hz\n", audioOutput->name, audioFormat->bits,
|
"channel audio at %i Hz\n", audioOutput->name, audioFormat->bits,
|
||||||
audioFormat->channels, audioFormat->sampleRate);
|
audioFormat->channels, audioFormat->sampleRate);
|
||||||
|
|
||||||
@ -160,7 +163,7 @@ static int pulse_openDevice(AudioOutput * audioOutput)
|
|||||||
|
|
||||||
static void pulse_dropBufferedAudio(AudioOutput * audioOutput)
|
static void pulse_dropBufferedAudio(AudioOutput * audioOutput)
|
||||||
{
|
{
|
||||||
PulseData * pd;
|
PulseData *pd;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
pd = audioOutput->data;
|
pd = audioOutput->data;
|
||||||
@ -171,7 +174,7 @@ static void pulse_dropBufferedAudio(AudioOutput * audioOutput)
|
|||||||
|
|
||||||
static void pulse_closeDevice(AudioOutput * audioOutput)
|
static void pulse_closeDevice(AudioOutput * audioOutput)
|
||||||
{
|
{
|
||||||
PulseData * pd;
|
PulseData *pd;
|
||||||
|
|
||||||
pd = audioOutput->data;
|
pd = audioOutput->data;
|
||||||
if (pd->s) {
|
if (pd->s) {
|
||||||
@ -182,16 +185,15 @@ static void pulse_closeDevice(AudioOutput * audioOutput)
|
|||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pulse_playAudio(AudioOutput * audioOutput, char * playChunk,
|
static int pulse_playAudio(AudioOutput * audioOutput, char *playChunk, int size)
|
||||||
int size)
|
|
||||||
{
|
{
|
||||||
PulseData * pd;
|
PulseData *pd;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
pd = audioOutput->data;
|
pd = audioOutput->data;
|
||||||
|
|
||||||
if (pa_simple_write(pd->s, playChunk, size, &error) < 0) {
|
if (pa_simple_write(pd->s, playChunk, size, &error) < 0) {
|
||||||
ERROR("PulseAudio output \"%s\" disconnecting due to write " \
|
ERROR("PulseAudio output \"%s\" disconnecting due to write "
|
||||||
"error: %s\n", audioOutput->name, pa_strerror(error));
|
"error: %s\n", audioOutput->name, pa_strerror(error));
|
||||||
pulse_closeDevice(audioOutput);
|
pulse_closeDevice(audioOutput);
|
||||||
return -1;
|
return -1;
|
||||||
@ -215,5 +217,4 @@ AudioOutputPlugin pulsePlugin = {
|
|||||||
#else /* HAVE_PULSE */
|
#else /* HAVE_PULSE */
|
||||||
|
|
||||||
DISABLED_AUDIO_OUTPUT_PLUGIN(pulsePlugin)
|
DISABLED_AUDIO_OUTPUT_PLUGIN(pulsePlugin)
|
||||||
|
|
||||||
#endif /* HAVE_PULSE */
|
#endif /* HAVE_PULSE */
|
||||||
|
@ -42,7 +42,7 @@ static int shoutInitCount = 0;
|
|||||||
/* lots of this code blatantly stolent from bossogg/bossao2 */
|
/* lots of this code blatantly stolent from bossogg/bossao2 */
|
||||||
|
|
||||||
typedef struct _ShoutData {
|
typedef struct _ShoutData {
|
||||||
shout_t * shoutConn;
|
shout_t *shoutConn;
|
||||||
int shoutError;
|
int shoutError;
|
||||||
|
|
||||||
ogg_stream_state os;
|
ogg_stream_state os;
|
||||||
@ -62,18 +62,19 @@ typedef struct _ShoutData {
|
|||||||
|
|
||||||
int opened;
|
int opened;
|
||||||
|
|
||||||
MpdTag * tag;
|
MpdTag *tag;
|
||||||
int tagToSend;
|
int tagToSend;
|
||||||
|
|
||||||
int connAttempts;
|
int connAttempts;
|
||||||
time_t lastAttempt;
|
time_t lastAttempt;
|
||||||
|
|
||||||
/* just a pointer to audioOutput->outAudioFormat */
|
/* just a pointer to audioOutput->outAudioFormat */
|
||||||
AudioFormat * audioFormat;
|
AudioFormat *audioFormat;
|
||||||
} ShoutData;
|
} ShoutData;
|
||||||
|
|
||||||
static ShoutData * newShoutData(void) {
|
static ShoutData *newShoutData(void)
|
||||||
ShoutData * ret = malloc(sizeof(ShoutData));
|
{
|
||||||
|
ShoutData *ret = malloc(sizeof(ShoutData));
|
||||||
|
|
||||||
ret->shoutConn = shout_new();
|
ret->shoutConn = shout_new();
|
||||||
ret->opened = 0;
|
ret->opened = 0;
|
||||||
@ -88,9 +89,12 @@ static ShoutData * newShoutData(void) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeShoutData(ShoutData * sd) {
|
static void freeShoutData(ShoutData * sd)
|
||||||
if(sd->shoutConn) shout_free(sd->shoutConn);
|
{
|
||||||
if(sd->tag) freeMpdTag(sd->tag);
|
if (sd->shoutConn)
|
||||||
|
shout_free(sd->shoutConn);
|
||||||
|
if (sd->tag)
|
||||||
|
freeMpdTag(sd->tag);
|
||||||
|
|
||||||
free(sd);
|
free(sd);
|
||||||
}
|
}
|
||||||
@ -104,21 +108,23 @@ static void freeShoutData(ShoutData * sd) {
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
|
||||||
ShoutData * sd;
|
{
|
||||||
char * test;
|
ShoutData *sd;
|
||||||
|
char *test;
|
||||||
int port;
|
int port;
|
||||||
char * host;
|
char *host;
|
||||||
char * mount;
|
char *mount;
|
||||||
char * passwd;
|
char *passwd;
|
||||||
char * user;
|
char *user;
|
||||||
char * name;
|
char *name;
|
||||||
BlockParam * blockParam;
|
BlockParam *blockParam;
|
||||||
unsigned int public;
|
unsigned int public;
|
||||||
|
|
||||||
sd = newShoutData();
|
sd = newShoutData();
|
||||||
|
|
||||||
if(shoutInitCount == 0) shout_init();
|
if (shoutInitCount == 0)
|
||||||
|
shout_init();
|
||||||
|
|
||||||
shoutInitCount++;
|
shoutInitCount++;
|
||||||
|
|
||||||
@ -132,7 +138,7 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
|||||||
|
|
||||||
port = strtol(blockParam->value, &test, 10);
|
port = strtol(blockParam->value, &test, 10);
|
||||||
|
|
||||||
if(*test != '\0' || port <= 0) {
|
if (*test != '\0' || port <= 0) {
|
||||||
ERROR("shout port \"%s\" is not a positive integer, line %i\n",
|
ERROR("shout port \"%s\" is not a positive integer, line %i\n",
|
||||||
blockParam->value, blockParam->line);
|
blockParam->value, blockParam->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -145,29 +151,33 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
|||||||
name = blockParam->value;
|
name = blockParam->value;
|
||||||
|
|
||||||
blockParam = getBlockParam(param, "public");
|
blockParam = getBlockParam(param, "public");
|
||||||
if(blockParam) {
|
if (blockParam) {
|
||||||
if(0 == strcmp(blockParam->value, "yes")) public = 1;
|
if (0 == strcmp(blockParam->value, "yes"))
|
||||||
else if(0 == strcmp(blockParam->value, "no")) public = 0;
|
public = 1;
|
||||||
|
else if (0 == strcmp(blockParam->value, "no"))
|
||||||
|
public = 0;
|
||||||
else {
|
else {
|
||||||
ERROR("public \"%s\" is not \"yes\" or \"no\" at line "
|
ERROR("public \"%s\" is not \"yes\" or \"no\" at line "
|
||||||
"%i\n", param->value, param->line);
|
"%i\n", param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else public = 0;
|
public = 0;
|
||||||
|
|
||||||
blockParam = getBlockParam(param, "user");
|
blockParam = getBlockParam(param, "user");
|
||||||
if(blockParam) user = blockParam->value;
|
if (blockParam)
|
||||||
else user = "source";
|
user = blockParam->value;
|
||||||
|
else
|
||||||
|
user = "source";
|
||||||
|
|
||||||
blockParam = getBlockParam(param, "quality");
|
blockParam = getBlockParam(param, "quality");
|
||||||
|
|
||||||
if(blockParam) {
|
if (blockParam) {
|
||||||
int line = blockParam->line;
|
int line = blockParam->line;
|
||||||
|
|
||||||
sd->quality = strtod(blockParam->value, &test);
|
sd->quality = strtod(blockParam->value, &test);
|
||||||
|
|
||||||
if(*test != '\0' || sd->quality < 0.0 || sd->quality > 10.0) {
|
if (*test != '\0' || sd->quality < 0.0 || sd->quality > 10.0) {
|
||||||
ERROR("shout quality \"%s\" is not a number in the "
|
ERROR("shout quality \"%s\" is not a number in the "
|
||||||
"range 0-10, line %i\n", blockParam->value,
|
"range 0-10, line %i\n", blockParam->value,
|
||||||
blockParam->line);
|
blockParam->line);
|
||||||
@ -176,17 +186,16 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
|||||||
|
|
||||||
blockParam = getBlockParam(param, "bitrate");
|
blockParam = getBlockParam(param, "bitrate");
|
||||||
|
|
||||||
if(blockParam) {
|
if (blockParam) {
|
||||||
ERROR("quality (line %i) and bitrate (line %i) are "
|
ERROR("quality (line %i) and bitrate (line %i) are "
|
||||||
"both defined for shout output\n", line,
|
"both defined for shout output\n", line,
|
||||||
blockParam->line);
|
blockParam->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
blockParam = getBlockParam(param, "bitrate");
|
blockParam = getBlockParam(param, "bitrate");
|
||||||
|
|
||||||
if(!blockParam) {
|
if (!blockParam) {
|
||||||
ERROR("neither bitrate nor quality defined for shout "
|
ERROR("neither bitrate nor quality defined for shout "
|
||||||
"output at line %i\n", param->line);
|
"output at line %i\n", param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -194,7 +203,7 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
|||||||
|
|
||||||
sd->bitrate = strtol(blockParam->value, &test, 10);
|
sd->bitrate = strtol(blockParam->value, &test, 10);
|
||||||
|
|
||||||
if(*test != '\0' || sd->bitrate <= 0) {
|
if (*test != '\0' || sd->bitrate <= 0) {
|
||||||
ERROR("bitrate at line %i should be a positive integer "
|
ERROR("bitrate at line %i should be a positive integer "
|
||||||
"\n", blockParam->line);
|
"\n", blockParam->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -204,7 +213,7 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
|||||||
checkBlockParam("format");
|
checkBlockParam("format");
|
||||||
sd->audioFormat = &audioOutput->outAudioFormat;
|
sd->audioFormat = &audioOutput->outAudioFormat;
|
||||||
|
|
||||||
if(shout_set_host(sd->shoutConn, host) != SHOUTERR_SUCCESS ||
|
if (shout_set_host(sd->shoutConn, host) != SHOUTERR_SUCCESS ||
|
||||||
shout_set_port(sd->shoutConn, port) != SHOUTERR_SUCCESS ||
|
shout_set_port(sd->shoutConn, port) != SHOUTERR_SUCCESS ||
|
||||||
shout_set_password(sd->shoutConn, passwd) != SHOUTERR_SUCCESS ||
|
shout_set_password(sd->shoutConn, passwd) != SHOUTERR_SUCCESS ||
|
||||||
shout_set_mount(sd->shoutConn, mount) != SHOUTERR_SUCCESS ||
|
shout_set_mount(sd->shoutConn, mount) != SHOUTERR_SUCCESS ||
|
||||||
@ -215,30 +224,25 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
|||||||
!= SHOUTERR_SUCCESS ||
|
!= SHOUTERR_SUCCESS ||
|
||||||
shout_set_protocol(sd->shoutConn, SHOUT_PROTOCOL_HTTP)
|
shout_set_protocol(sd->shoutConn, SHOUT_PROTOCOL_HTTP)
|
||||||
!= SHOUTERR_SUCCESS ||
|
!= SHOUTERR_SUCCESS ||
|
||||||
shout_set_agent(sd->shoutConn, "MPD") != SHOUTERR_SUCCESS)
|
shout_set_agent(sd->shoutConn, "MPD") != SHOUTERR_SUCCESS) {
|
||||||
{
|
|
||||||
ERROR("error configuring shout defined at line %i: %s\n",
|
ERROR("error configuring shout defined at line %i: %s\n",
|
||||||
param->line,
|
param->line, shout_get_error(sd->shoutConn));
|
||||||
shout_get_error(sd->shoutConn));
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* optional paramters */
|
/* optional paramters */
|
||||||
blockParam = getBlockParam(param, "genre");
|
blockParam = getBlockParam(param, "genre");
|
||||||
if(blockParam && shout_set_genre(sd->shoutConn, blockParam->value)) {
|
if (blockParam && shout_set_genre(sd->shoutConn, blockParam->value)) {
|
||||||
ERROR("error configuring shout defined at line %i: %s\n",
|
ERROR("error configuring shout defined at line %i: %s\n",
|
||||||
param->line,
|
param->line, shout_get_error(sd->shoutConn));
|
||||||
shout_get_error(sd->shoutConn));
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
blockParam = getBlockParam(param, "description");
|
blockParam = getBlockParam(param, "description");
|
||||||
if(blockParam && shout_set_description(sd->shoutConn,
|
if (blockParam && shout_set_description(sd->shoutConn,
|
||||||
blockParam->value))
|
blockParam->value)) {
|
||||||
{
|
|
||||||
ERROR("error configuring shout defined at line %i: %s\n",
|
ERROR("error configuring shout defined at line %i: %s\n",
|
||||||
param->line,
|
param->line, shout_get_error(sd->shoutConn));
|
||||||
shout_get_error(sd->shoutConn));
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,12 +257,11 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
|||||||
|
|
||||||
shout_set_audio_info(sd->shoutConn, SHOUT_AI_SAMPLERATE, temp);
|
shout_set_audio_info(sd->shoutConn, SHOUT_AI_SAMPLERATE, temp);
|
||||||
|
|
||||||
if(sd->quality >= 0) {
|
if (sd->quality >= 0) {
|
||||||
snprintf(temp, sizeof(temp), "%2.2f", sd->quality);
|
snprintf(temp, sizeof(temp), "%2.2f", sd->quality);
|
||||||
shout_set_audio_info(sd->shoutConn, SHOUT_AI_QUALITY,
|
shout_set_audio_info(sd->shoutConn, SHOUT_AI_QUALITY,
|
||||||
temp);
|
temp);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
snprintf(temp, sizeof(temp), "%d", sd->bitrate);
|
snprintf(temp, sizeof(temp), "%d", sd->bitrate);
|
||||||
shout_set_audio_info(sd->shoutConn, SHOUT_AI_BITRATE,
|
shout_set_audio_info(sd->shoutConn, SHOUT_AI_BITRATE,
|
||||||
temp);
|
temp);
|
||||||
@ -270,8 +273,9 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int myShout_handleError(ShoutData * sd, int err) {
|
static int myShout_handleError(ShoutData * sd, int err)
|
||||||
switch(err) {
|
{
|
||||||
|
switch (err) {
|
||||||
case SHOUTERR_SUCCESS:
|
case SHOUTERR_SUCCESS:
|
||||||
break;
|
break;
|
||||||
case SHOUTERR_UNCONNECTED:
|
case SHOUTERR_UNCONNECTED:
|
||||||
@ -294,39 +298,46 @@ static int myShout_handleError(ShoutData * sd, int err) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_page(ShoutData * sd) {
|
static int write_page(ShoutData * sd)
|
||||||
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
/*DEBUG("shout_delay: %i\n", shout_delay(sd->shoutConn));*/
|
/*DEBUG("shout_delay: %i\n", shout_delay(sd->shoutConn)); */
|
||||||
shout_sync(sd->shoutConn);
|
shout_sync(sd->shoutConn);
|
||||||
err = shout_send(sd->shoutConn, sd->og.header, sd->og.header_len);
|
err = shout_send(sd->shoutConn, sd->og.header, sd->og.header_len);
|
||||||
if(myShout_handleError(sd, err) < 0) return -1;
|
if (myShout_handleError(sd, err) < 0)
|
||||||
|
return -1;
|
||||||
err = shout_send(sd->shoutConn, sd->og.body, sd->og.body_len);
|
err = shout_send(sd->shoutConn, sd->og.body, sd->og.body_len);
|
||||||
if(myShout_handleError(sd, err) < 0) return -1;
|
if (myShout_handleError(sd, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void finishEncoder(ShoutData * sd) {
|
static void finishEncoder(ShoutData * sd)
|
||||||
|
{
|
||||||
vorbis_analysis_wrote(&sd->vd, 0);
|
vorbis_analysis_wrote(&sd->vd, 0);
|
||||||
|
|
||||||
while(vorbis_analysis_blockout(&sd->vd, &sd->vb) == 1) {
|
while (vorbis_analysis_blockout(&sd->vd, &sd->vb) == 1) {
|
||||||
vorbis_analysis(&sd->vb, NULL);
|
vorbis_analysis(&sd->vb, NULL);
|
||||||
vorbis_bitrate_addblock(&sd->vb);
|
vorbis_bitrate_addblock(&sd->vb);
|
||||||
while(vorbis_bitrate_flushpacket(&sd->vd, &sd->op)) {
|
while (vorbis_bitrate_flushpacket(&sd->vd, &sd->op)) {
|
||||||
ogg_stream_packetin(&sd->os, &sd->op);
|
ogg_stream_packetin(&sd->os, &sd->op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flushEncoder(ShoutData * sd) {
|
static int flushEncoder(ShoutData * sd)
|
||||||
|
{
|
||||||
return (ogg_stream_pageout(&sd->os, &sd->og) > 0);
|
return (ogg_stream_pageout(&sd->os, &sd->og) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearEncoder(ShoutData * sd) {
|
static void clearEncoder(ShoutData * sd)
|
||||||
|
{
|
||||||
finishEncoder(sd);
|
finishEncoder(sd);
|
||||||
while(1 == flushEncoder(sd)) {
|
while (1 == flushEncoder(sd)) {
|
||||||
if(!sd->shoutError) write_page(sd);
|
if (!sd->shoutError)
|
||||||
|
write_page(sd);
|
||||||
}
|
}
|
||||||
|
|
||||||
vorbis_comment_clear(&sd->vc);
|
vorbis_comment_clear(&sd->vc);
|
||||||
@ -336,11 +347,12 @@ static void clearEncoder(ShoutData * sd) {
|
|||||||
vorbis_info_clear(&sd->vi);
|
vorbis_info_clear(&sd->vi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void myShout_closeShoutConn(ShoutData * sd) {
|
static void myShout_closeShoutConn(ShoutData * sd)
|
||||||
if(sd->opened) {
|
{
|
||||||
|
if (sd->opened) {
|
||||||
clearEncoder(sd);
|
clearEncoder(sd);
|
||||||
|
|
||||||
if(shout_close(sd->shoutConn) != SHOUTERR_SUCCESS) {
|
if (shout_close(sd->shoutConn) != SHOUTERR_SUCCESS) {
|
||||||
ERROR("problem closing connection to shout server: "
|
ERROR("problem closing connection to shout server: "
|
||||||
"%s\n", shout_get_error(sd->shoutConn));
|
"%s\n", shout_get_error(sd->shoutConn));
|
||||||
}
|
}
|
||||||
@ -349,8 +361,9 @@ static void myShout_closeShoutConn(ShoutData * sd) {
|
|||||||
sd->opened = 0;
|
sd->opened = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void myShout_finishDriver(AudioOutput * audioOutput) {
|
static void myShout_finishDriver(AudioOutput * audioOutput)
|
||||||
ShoutData * sd = (ShoutData *)audioOutput->data;
|
{
|
||||||
|
ShoutData *sd = (ShoutData *) audioOutput->data;
|
||||||
|
|
||||||
myShout_closeShoutConn(sd);
|
myShout_closeShoutConn(sd);
|
||||||
|
|
||||||
@ -358,15 +371,18 @@ static void myShout_finishDriver(AudioOutput * audioOutput) {
|
|||||||
|
|
||||||
shoutInitCount--;
|
shoutInitCount--;
|
||||||
|
|
||||||
if(shoutInitCount == 0) shout_shutdown();
|
if (shoutInitCount == 0)
|
||||||
|
shout_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void myShout_dropBufferedAudio(AudioOutput * audioOutput) {
|
static void myShout_dropBufferedAudio(AudioOutput * audioOutput)
|
||||||
|
{
|
||||||
/* needs to be implemented */
|
/* needs to be implemented */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void myShout_closeDevice(AudioOutput * audioOutput) {
|
static void myShout_closeDevice(AudioOutput * audioOutput)
|
||||||
ShoutData * sd = (ShoutData *)audioOutput->data;
|
{
|
||||||
|
ShoutData *sd = (ShoutData *) audioOutput->data;
|
||||||
|
|
||||||
myShout_closeShoutConn(sd);
|
myShout_closeShoutConn(sd);
|
||||||
|
|
||||||
@ -377,12 +393,13 @@ static void myShout_closeDevice(AudioOutput * audioOutput) {
|
|||||||
if(value) vorbis_comment_add_tag(&(sd->vc), name, value); \
|
if(value) vorbis_comment_add_tag(&(sd->vc), name, value); \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void copyTagToVorbisComment(ShoutData * sd) {
|
static void copyTagToVorbisComment(ShoutData * sd)
|
||||||
if(sd->tag) {
|
{
|
||||||
|
if (sd->tag) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < sd->tag->numOfItems; i++) {
|
for (i = 0; i < sd->tag->numOfItems; i++) {
|
||||||
switch(sd->tag->items[i].type) {
|
switch (sd->tag->items[i].type) {
|
||||||
case TAG_ITEM_ARTIST:
|
case TAG_ITEM_ARTIST:
|
||||||
addTag("ARTIST", sd->tag->items[i].value);
|
addTag("ARTIST", sd->tag->items[i].value);
|
||||||
break;
|
break;
|
||||||
@ -397,25 +414,24 @@ static void copyTagToVorbisComment(ShoutData * sd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int initEncoder(ShoutData * sd) {
|
static int initEncoder(ShoutData * sd)
|
||||||
|
{
|
||||||
vorbis_info_init(&(sd->vi));
|
vorbis_info_init(&(sd->vi));
|
||||||
|
|
||||||
if(sd->quality >= 0) {
|
if (sd->quality >= 0) {
|
||||||
if( 0 != vorbis_encode_init_vbr(&(sd->vi),
|
if (0 != vorbis_encode_init_vbr(&(sd->vi),
|
||||||
sd->audioFormat->channels,
|
sd->audioFormat->channels,
|
||||||
sd->audioFormat->sampleRate, sd->quality*0.1) )
|
sd->audioFormat->sampleRate,
|
||||||
{
|
sd->quality * 0.1)) {
|
||||||
ERROR("problem seting up vorbis encoder for shout\n");
|
ERROR("problem seting up vorbis encoder for shout\n");
|
||||||
vorbis_info_clear(&(sd->vi));
|
vorbis_info_clear(&(sd->vi));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (0 != vorbis_encode_init(&(sd->vi),
|
||||||
if( 0 != vorbis_encode_init(&(sd->vi),
|
|
||||||
sd->audioFormat->channels,
|
sd->audioFormat->channels,
|
||||||
sd->audioFormat->sampleRate, -1.0,
|
sd->audioFormat->sampleRate, -1.0,
|
||||||
sd->bitrate*1000, -1.0) )
|
sd->bitrate * 1000, -1.0)) {
|
||||||
{
|
|
||||||
ERROR("problem seting up vorbis encoder for shout\n");
|
ERROR("problem seting up vorbis encoder for shout\n");
|
||||||
vorbis_info_clear(&(sd->vi));
|
vorbis_info_clear(&(sd->vi));
|
||||||
return -1;
|
return -1;
|
||||||
@ -423,7 +439,7 @@ static int initEncoder(ShoutData * sd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vorbis_analysis_init(&(sd->vd), &(sd->vi));
|
vorbis_analysis_init(&(sd->vd), &(sd->vi));
|
||||||
vorbis_block_init (&(sd->vd), &(sd->vb));
|
vorbis_block_init(&(sd->vd), &(sd->vb));
|
||||||
|
|
||||||
ogg_stream_init(&(sd->os), rand());
|
ogg_stream_init(&(sd->os), rand());
|
||||||
|
|
||||||
@ -432,13 +448,13 @@ static int initEncoder(ShoutData * sd) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int myShout_openShoutConn(AudioOutput * audioOutput) {
|
static int myShout_openShoutConn(AudioOutput * audioOutput)
|
||||||
ShoutData * sd = (ShoutData *)audioOutput->data;
|
{
|
||||||
|
ShoutData *sd = (ShoutData *) audioOutput->data;
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
|
|
||||||
if(sd->connAttempts!= 0 &&
|
if (sd->connAttempts != 0 &&
|
||||||
(t - sd->lastAttempt) < CONN_ATTEMPT_INTERVAL)
|
(t - sd->lastAttempt) < CONN_ATTEMPT_INTERVAL) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,17 +462,16 @@ static int myShout_openShoutConn(AudioOutput * audioOutput) {
|
|||||||
|
|
||||||
sd->lastAttempt = t;
|
sd->lastAttempt = t;
|
||||||
|
|
||||||
if(shout_open(sd->shoutConn) != SHOUTERR_SUCCESS) {
|
if (shout_open(sd->shoutConn) != SHOUTERR_SUCCESS) {
|
||||||
ERROR("problem opening connection to shout server %s:%i "
|
ERROR("problem opening connection to shout server %s:%i "
|
||||||
"(attempt %i): %s\n",
|
"(attempt %i): %s\n",
|
||||||
shout_get_host(sd->shoutConn),
|
shout_get_host(sd->shoutConn),
|
||||||
shout_get_port(sd->shoutConn),
|
shout_get_port(sd->shoutConn),
|
||||||
sd->connAttempts,
|
sd->connAttempts, shout_get_error(sd->shoutConn));
|
||||||
shout_get_error(sd->shoutConn));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(initEncoder(sd) < 0) {
|
if (initEncoder(sd) < 0) {
|
||||||
shout_close(sd->shoutConn);
|
shout_close(sd->shoutConn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -466,7 +481,8 @@ static int myShout_openShoutConn(AudioOutput * audioOutput) {
|
|||||||
copyTagToVorbisComment(sd);
|
copyTagToVorbisComment(sd);
|
||||||
|
|
||||||
vorbis_analysis_headerout(&(sd->vd), &(sd->vc), &(sd->header_main),
|
vorbis_analysis_headerout(&(sd->vd), &(sd->vc), &(sd->header_main),
|
||||||
&(sd->header_comments), &(sd->header_codebooks));
|
&(sd->header_comments),
|
||||||
|
&(sd->header_codebooks));
|
||||||
|
|
||||||
ogg_stream_packetin(&(sd->os), &(sd->header_main));
|
ogg_stream_packetin(&(sd->os), &(sd->header_main));
|
||||||
ogg_stream_packetin(&(sd->os), &(sd->header_comments));
|
ogg_stream_packetin(&(sd->os), &(sd->header_comments));
|
||||||
@ -475,9 +491,8 @@ static int myShout_openShoutConn(AudioOutput * audioOutput) {
|
|||||||
sd->opened = 1;
|
sd->opened = 1;
|
||||||
sd->tagToSend = 0;
|
sd->tagToSend = 0;
|
||||||
|
|
||||||
while(ogg_stream_flush(&(sd->os), &(sd->og)))
|
while (ogg_stream_flush(&(sd->os), &(sd->og))) {
|
||||||
{
|
if (write_page(sd) < 0) {
|
||||||
if(write_page(sd) < 0) {
|
|
||||||
myShout_closeShoutConn(sd);
|
myShout_closeShoutConn(sd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -488,14 +503,16 @@ static int myShout_openShoutConn(AudioOutput * audioOutput) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int myShout_openDevice(AudioOutput * audioOutput) {
|
static int myShout_openDevice(AudioOutput * audioOutput)
|
||||||
ShoutData * sd = (ShoutData *)audioOutput->data;
|
{
|
||||||
|
ShoutData *sd = (ShoutData *) audioOutput->data;
|
||||||
|
|
||||||
audioOutput->open = 1;
|
audioOutput->open = 1;
|
||||||
|
|
||||||
if(sd->opened) return 0;
|
if (sd->opened)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if(myShout_openShoutConn(audioOutput) < 0) {
|
if (myShout_openShoutConn(audioOutput) < 0) {
|
||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -503,76 +520,80 @@ static int myShout_openDevice(AudioOutput * audioOutput) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void myShout_sendMetadata(ShoutData * sd) {
|
static void myShout_sendMetadata(ShoutData * sd)
|
||||||
if(!sd->opened || !sd->tag) return;
|
{
|
||||||
|
if (!sd->opened || !sd->tag)
|
||||||
|
return;
|
||||||
|
|
||||||
clearEncoder(sd);
|
clearEncoder(sd);
|
||||||
if(initEncoder(sd) < 0) return;
|
if (initEncoder(sd) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
copyTagToVorbisComment(sd);
|
copyTagToVorbisComment(sd);
|
||||||
|
|
||||||
vorbis_analysis_headerout(&(sd->vd), &(sd->vc), &(sd->header_main),
|
vorbis_analysis_headerout(&(sd->vd), &(sd->vc), &(sd->header_main),
|
||||||
&(sd->header_comments), &(sd->header_codebooks));
|
&(sd->header_comments),
|
||||||
|
&(sd->header_codebooks));
|
||||||
|
|
||||||
ogg_stream_packetin(&(sd->os), &(sd->header_main));
|
ogg_stream_packetin(&(sd->os), &(sd->header_main));
|
||||||
ogg_stream_packetin(&(sd->os), &(sd->header_comments));
|
ogg_stream_packetin(&(sd->os), &(sd->header_comments));
|
||||||
ogg_stream_packetin(&(sd->os), &(sd->header_codebooks));
|
ogg_stream_packetin(&(sd->os), &(sd->header_codebooks));
|
||||||
|
|
||||||
while(ogg_stream_flush(&(sd->os), &(sd->og)))
|
while (ogg_stream_flush(&(sd->os), &(sd->og))) {
|
||||||
{
|
if (write_page(sd) < 0) {
|
||||||
if(write_page(sd) < 0) {
|
|
||||||
myShout_closeShoutConn(sd);
|
myShout_closeShoutConn(sd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if(sd->tag) freeMpdTag(sd->tag);
|
/*if(sd->tag) freeMpdTag(sd->tag);
|
||||||
sd->tag = NULL;*/
|
sd->tag = NULL; */
|
||||||
sd->tagToSend = 0;
|
sd->tagToSend = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int myShout_play(AudioOutput * audioOutput, char * playChunk, int size) {
|
static int myShout_play(AudioOutput * audioOutput, char *playChunk, int size)
|
||||||
int i,j;
|
{
|
||||||
ShoutData * sd = (ShoutData *)audioOutput->data;
|
int i, j;
|
||||||
float ** vorbbuf;
|
ShoutData *sd = (ShoutData *) audioOutput->data;
|
||||||
|
float **vorbbuf;
|
||||||
int samples;
|
int samples;
|
||||||
int bytes = sd->audioFormat->bits/8;
|
int bytes = sd->audioFormat->bits / 8;
|
||||||
|
|
||||||
if(sd->opened && sd->tagToSend) myShout_sendMetadata(sd);
|
if (sd->opened && sd->tagToSend)
|
||||||
|
myShout_sendMetadata(sd);
|
||||||
|
|
||||||
if(!sd->opened) {
|
if (!sd->opened) {
|
||||||
if(myShout_openShoutConn(audioOutput) < 0) {
|
if (myShout_openShoutConn(audioOutput) < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
samples = size/(bytes*sd->audioFormat->channels);
|
samples = size / (bytes * sd->audioFormat->channels);
|
||||||
|
|
||||||
/* this is for only 16-bit audio */
|
/* this is for only 16-bit audio */
|
||||||
|
|
||||||
vorbbuf = vorbis_analysis_buffer(&(sd->vd), samples);
|
vorbbuf = vorbis_analysis_buffer(&(sd->vd), samples);
|
||||||
|
|
||||||
for(i=0; i<samples; i++) {
|
for (i = 0; i < samples; i++) {
|
||||||
for(j=0; j<sd->audioFormat->channels; j++) {
|
for (j = 0; j < sd->audioFormat->channels; j++) {
|
||||||
vorbbuf[j][i] = (*((mpd_sint16 *)playChunk)) / 32768.0;
|
vorbbuf[j][i] = (*((mpd_sint16 *) playChunk)) / 32768.0;
|
||||||
playChunk += bytes;
|
playChunk += bytes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vorbis_analysis_wrote(&(sd->vd), samples);
|
vorbis_analysis_wrote(&(sd->vd), samples);
|
||||||
|
|
||||||
while(1 == vorbis_analysis_blockout(&(sd->vd), &(sd->vb))) {
|
while (1 == vorbis_analysis_blockout(&(sd->vd), &(sd->vb))) {
|
||||||
vorbis_analysis(&(sd->vb), NULL);
|
vorbis_analysis(&(sd->vb), NULL);
|
||||||
vorbis_bitrate_addblock(&(sd->vb));
|
vorbis_bitrate_addblock(&(sd->vb));
|
||||||
|
|
||||||
while(vorbis_bitrate_flushpacket(&(sd->vd), &(sd->op))) {
|
while (vorbis_bitrate_flushpacket(&(sd->vd), &(sd->op))) {
|
||||||
ogg_stream_packetin(&(sd->os), &(sd->op));
|
ogg_stream_packetin(&(sd->os), &(sd->op));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (ogg_stream_pageout(&(sd->os), &(sd->og)) != 0) {
|
||||||
while(ogg_stream_pageout(&(sd->os), &(sd->og)) != 0) {
|
if (write_page(sd) < 0) {
|
||||||
if(write_page(sd) < 0) {
|
|
||||||
myShout_closeShoutConn(sd);
|
myShout_closeShoutConn(sd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -581,21 +602,23 @@ static int myShout_play(AudioOutput * audioOutput, char * playChunk, int size) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void myShout_setTag(AudioOutput * audioOutput, MpdTag * tag) {
|
static void myShout_setTag(AudioOutput * audioOutput, MpdTag * tag)
|
||||||
ShoutData * sd = (ShoutData *)audioOutput->data;
|
{
|
||||||
|
ShoutData *sd = (ShoutData *) audioOutput->data;
|
||||||
|
|
||||||
if(sd->tag) freeMpdTag(sd->tag);
|
if (sd->tag)
|
||||||
|
freeMpdTag(sd->tag);
|
||||||
sd->tag = NULL;
|
sd->tag = NULL;
|
||||||
sd->tagToSend = 0;
|
sd->tagToSend = 0;
|
||||||
|
|
||||||
if(!tag) return;
|
if (!tag)
|
||||||
|
return;
|
||||||
|
|
||||||
sd->tag = mpdTagDup(tag);
|
sd->tag = mpdTagDup(tag);
|
||||||
sd->tagToSend = 1;
|
sd->tagToSend = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioOutputPlugin shoutPlugin =
|
AudioOutputPlugin shoutPlugin = {
|
||||||
{
|
|
||||||
"shout",
|
"shout",
|
||||||
NULL,
|
NULL,
|
||||||
myShout_initDriver,
|
myShout_initDriver,
|
||||||
@ -610,5 +633,4 @@ AudioOutputPlugin shoutPlugin =
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
DISABLED_AUDIO_OUTPUT_PLUGIN(shoutPlugin)
|
DISABLED_AUDIO_OUTPUT_PLUGIN(shoutPlugin)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,79 +22,74 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
int buffer2array(char * origBuffer, char *** array) {
|
int buffer2array(char *origBuffer, char ***array)
|
||||||
|
{
|
||||||
int quotes = 0;
|
int quotes = 0;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int i;
|
int i;
|
||||||
int curr;
|
int curr;
|
||||||
int * beginArray;
|
int *beginArray;
|
||||||
char * buffer = strdup(origBuffer);
|
char *buffer = strdup(origBuffer);
|
||||||
int bufferLength = strlen(buffer);
|
int bufferLength = strlen(buffer);
|
||||||
char * markArray = malloc(sizeof(char)*(bufferLength+1));
|
char *markArray = malloc(sizeof(char) * (bufferLength + 1));
|
||||||
|
|
||||||
for(curr=0;curr<bufferLength;curr++) {
|
for (curr = 0; curr < bufferLength; curr++) {
|
||||||
if(!quotes && (buffer[curr]==' ' || buffer[curr]=='\t') ) {
|
if (!quotes && (buffer[curr] == ' ' || buffer[curr] == '\t')) {
|
||||||
markArray[curr] = '0';
|
markArray[curr] = '0';
|
||||||
}
|
} else if (buffer[curr] == '\"') {
|
||||||
else if(buffer[curr] == '\"') {
|
if (curr > 0 && buffer[curr - 1] != '\\') {
|
||||||
if(curr>0 && buffer[curr-1]!='\\') {
|
quotes = quotes ? 0 : 1;
|
||||||
quotes = quotes?0:1;
|
|
||||||
markArray[curr] = '0';
|
markArray[curr] = '0';
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
markArray[curr] = '1';
|
markArray[curr] = '1';
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
markArray[curr] = '1';
|
markArray[curr] = '1';
|
||||||
}
|
}
|
||||||
if(markArray[curr]=='1') {
|
if (markArray[curr] == '1') {
|
||||||
if(curr>0) {
|
if (curr > 0) {
|
||||||
if(markArray[curr-1]=='0') {
|
if (markArray[curr - 1] == '0') {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
markArray[bufferLength] = '\0';
|
markArray[bufferLength] = '\0';
|
||||||
|
|
||||||
if(!count) {
|
if (!count) {
|
||||||
free(buffer);
|
free(buffer);
|
||||||
free(markArray);
|
free(markArray);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
beginArray = malloc(sizeof(int)*count);
|
beginArray = malloc(sizeof(int) * count);
|
||||||
(*array) = malloc(sizeof(char *)*count);
|
(*array) = malloc(sizeof(char *) * count);
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
for(curr=0;curr<bufferLength;curr++) {
|
for (curr = 0; curr < bufferLength; curr++) {
|
||||||
if(markArray[curr]=='1') {
|
if (markArray[curr] == '1') {
|
||||||
if(curr>0) {
|
if (curr > 0) {
|
||||||
if(markArray[curr-1]=='0') {
|
if (markArray[curr - 1] == '0') {
|
||||||
beginArray[count++] = curr;
|
beginArray[count++] = curr;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
beginArray[count++] = curr;
|
beginArray[count++] = curr;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
buffer[curr] = '\0';
|
buffer[curr] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0;i<count;i++) {
|
for (i = 0; i < count; i++) {
|
||||||
int len = strlen(buffer+beginArray[i])+1;
|
int len = strlen(buffer + beginArray[i]) + 1;
|
||||||
int arrayCurr = 0;
|
int arrayCurr = 0;
|
||||||
(*array)[i] = malloc(sizeof(char)*len);
|
(*array)[i] = malloc(sizeof(char) * len);
|
||||||
for(curr=beginArray[i];buffer[curr]!='\0';curr++) {
|
for (curr = beginArray[i]; buffer[curr] != '\0'; curr++) {
|
||||||
if(buffer[curr]=='\\') {
|
if (buffer[curr] == '\\') {
|
||||||
if(buffer[curr+1]!='\0') {
|
if (buffer[curr + 1] != '\0') {
|
||||||
curr++;
|
curr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,12 +105,14 @@ int buffer2array(char * origBuffer, char *** array) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeArgArray(char ** array, int argArrayLength) {
|
void freeArgArray(char **array, int argArrayLength)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(argArrayLength==0) return;
|
if (argArrayLength == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
for(i=0;i<argArrayLength;i++) {
|
for (i = 0; i < argArrayLength; i++) {
|
||||||
free(array[i]);
|
free(array[i]);
|
||||||
}
|
}
|
||||||
free(array);
|
free(array);
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
|
|
||||||
int buffer2array(char * buffer, char *** array);
|
int buffer2array(char *buffer, char ***array);
|
||||||
|
|
||||||
void freeArgArray(char ** array, int argArrayLength);
|
void freeArgArray(char **array, int argArrayLength);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -29,8 +29,8 @@
|
|||||||
iconv_t char_conv_iconv;
|
iconv_t char_conv_iconv;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char * char_conv_to = NULL;
|
char *char_conv_to = NULL;
|
||||||
char * char_conv_from = NULL;
|
char *char_conv_from = NULL;
|
||||||
mpd_sint8 char_conv_same = 0;
|
mpd_sint8 char_conv_same = 0;
|
||||||
mpd_sint8 char_conv_use_iconv = 0;
|
mpd_sint8 char_conv_use_iconv = 0;
|
||||||
|
|
||||||
@ -43,37 +43,37 @@ mpd_sint8 char_conv_latin1ToUtf8 = 0;
|
|||||||
|
|
||||||
static void closeCharSetConversion();
|
static void closeCharSetConversion();
|
||||||
|
|
||||||
int setCharSetConversion(char * to, char * from) {
|
int setCharSetConversion(char *to, char *from)
|
||||||
if(char_conv_to && char_conv_from &&
|
{
|
||||||
strcmp(to,char_conv_to)==0 && strcmp(from,char_conv_from)==0)
|
if (char_conv_to && char_conv_from &&
|
||||||
|
strcmp(to, char_conv_to) == 0 && strcmp(from, char_conv_from) == 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
closeCharSetConversion();
|
closeCharSetConversion();
|
||||||
|
|
||||||
if(0==strcmp(to,from)) {
|
if (0 == strcmp(to, from)) {
|
||||||
char_conv_same = 1;
|
char_conv_same = 1;
|
||||||
char_conv_to = strdup(to);
|
char_conv_to = strdup(to);
|
||||||
char_conv_from = strdup(from);
|
char_conv_from = strdup(from);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strcmp(to,"UTF-8")==0 && strcmp(from,"ISO-8859-1")==0) {
|
if (strcmp(to, "UTF-8") == 0 && strcmp(from, "ISO-8859-1") == 0) {
|
||||||
char_conv_latin1ToUtf8 = 1;
|
char_conv_latin1ToUtf8 = 1;
|
||||||
}
|
} else if (strcmp(to, "ISO-8859-1") == 0 && strcmp(from, "UTF-8") == 0) {
|
||||||
else if(strcmp(to,"ISO-8859-1")==0 && strcmp(from,"UTF-8")==0) {
|
|
||||||
char_conv_latin1ToUtf8 = -1;
|
char_conv_latin1ToUtf8 = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(char_conv_latin1ToUtf8!=0) {
|
if (char_conv_latin1ToUtf8 != 0) {
|
||||||
char_conv_to = strdup(to);
|
char_conv_to = strdup(to);
|
||||||
char_conv_from = strdup(from);
|
char_conv_from = strdup(from);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_ICONV
|
#ifdef HAVE_ICONV
|
||||||
if((char_conv_iconv = iconv_open(to,from))==(iconv_t)(-1)) return -1;
|
if ((char_conv_iconv = iconv_open(to, from)) == (iconv_t) (-1))
|
||||||
|
return -1;
|
||||||
|
|
||||||
char_conv_to = strdup(to);
|
char_conv_to = strdup(to);
|
||||||
char_conv_from = strdup(from);
|
char_conv_from = strdup(from);
|
||||||
@ -85,37 +85,42 @@ int setCharSetConversion(char * to, char * from) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * convStrDup(char * string) {
|
char *convStrDup(char *string)
|
||||||
if(!char_conv_to) return NULL;
|
{
|
||||||
|
if (!char_conv_to)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if(char_conv_same) return strdup(string);
|
if (char_conv_same)
|
||||||
|
return strdup(string);
|
||||||
|
|
||||||
#ifdef HAVE_ICONV
|
#ifdef HAVE_ICONV
|
||||||
if(char_conv_use_iconv) {
|
if (char_conv_use_iconv) {
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
size_t inleft = strlen(string);
|
size_t inleft = strlen(string);
|
||||||
char * ret;
|
char *ret;
|
||||||
size_t outleft;
|
size_t outleft;
|
||||||
size_t retlen = 0;
|
size_t retlen = 0;
|
||||||
size_t err;
|
size_t err;
|
||||||
char * bufferPtr;
|
char *bufferPtr;
|
||||||
|
|
||||||
ret = malloc(1);
|
ret = malloc(1);
|
||||||
ret[0] = '\0';
|
ret[0] = '\0';
|
||||||
|
|
||||||
while(inleft) {
|
while (inleft) {
|
||||||
bufferPtr = buffer;
|
bufferPtr = buffer;
|
||||||
outleft = BUFFER_SIZE;
|
outleft = BUFFER_SIZE;
|
||||||
err = iconv(char_conv_iconv,&string,&inleft,&bufferPtr,
|
err =
|
||||||
|
iconv(char_conv_iconv, &string, &inleft, &bufferPtr,
|
||||||
&outleft);
|
&outleft);
|
||||||
if(outleft==BUFFER_SIZE || (err<0 && errno!=E2BIG)) {
|
if (outleft == BUFFER_SIZE
|
||||||
|
|| (err < 0 && errno != E2BIG)) {
|
||||||
free(ret);
|
free(ret);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = realloc(ret,retlen+BUFFER_SIZE-outleft+1);
|
ret = realloc(ret, retlen + BUFFER_SIZE - outleft + 1);
|
||||||
memcpy(ret+retlen,buffer,BUFFER_SIZE-outleft);
|
memcpy(ret + retlen, buffer, BUFFER_SIZE - outleft);
|
||||||
retlen+=BUFFER_SIZE-outleft;
|
retlen += BUFFER_SIZE - outleft;
|
||||||
ret[retlen] = '\0';
|
ret[retlen] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +128,7 @@ char * convStrDup(char * string) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch(char_conv_latin1ToUtf8) {
|
switch (char_conv_latin1ToUtf8) {
|
||||||
case 1:
|
case 1:
|
||||||
return latin1StrToUtf8Dup(string);
|
return latin1StrToUtf8Dup(string);
|
||||||
break;
|
break;
|
||||||
@ -135,10 +140,12 @@ char * convStrDup(char * string) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void closeCharSetConversion(void) {
|
static void closeCharSetConversion(void)
|
||||||
if(char_conv_to) {
|
{
|
||||||
|
if (char_conv_to) {
|
||||||
#ifdef HAVE_ICONV
|
#ifdef HAVE_ICONV
|
||||||
if(char_conv_use_iconv) iconv_close(char_conv_iconv);
|
if (char_conv_use_iconv)
|
||||||
|
iconv_close(char_conv_iconv);
|
||||||
#endif
|
#endif
|
||||||
free(char_conv_to);
|
free(char_conv_to);
|
||||||
free(char_conv_from);
|
free(char_conv_from);
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
|
|
||||||
int setCharSetConversion(char * to, char * from);
|
int setCharSetConversion(char *to, char *from);
|
||||||
|
|
||||||
char * convStrDup(char * string);
|
char *convStrDup(char *string);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
894
src/command.c
894
src/command.c
File diff suppressed because it is too large
Load Diff
@ -32,13 +32,13 @@
|
|||||||
#define COMMAND_RETURN_CLOSE 20
|
#define COMMAND_RETURN_CLOSE 20
|
||||||
#define COMMAND_MASTER_READY 30
|
#define COMMAND_MASTER_READY 30
|
||||||
|
|
||||||
extern char * current_command;
|
extern char *current_command;
|
||||||
extern int command_listNum;
|
extern int command_listNum;
|
||||||
|
|
||||||
int processListOfCommands(FILE * fp, int * permission, int * expired,
|
int processListOfCommands(FILE * fp, int *permission, int *expired,
|
||||||
int listOK, List * list);
|
int listOK, List * list);
|
||||||
|
|
||||||
int processCommand(FILE * fp, int * permission, char * commandString);
|
int processCommand(FILE * fp, int *permission, char *commandString);
|
||||||
|
|
||||||
void initCommands();
|
void initCommands();
|
||||||
|
|
||||||
|
255
src/conf.c
255
src/conf.c
@ -44,16 +44,19 @@
|
|||||||
|
|
||||||
typedef struct _configEntry {
|
typedef struct _configEntry {
|
||||||
unsigned char mask;
|
unsigned char mask;
|
||||||
List * configParamList;
|
List *configParamList;
|
||||||
} ConfigEntry;
|
} ConfigEntry;
|
||||||
|
|
||||||
static List * configEntriesList = NULL;
|
static List *configEntriesList = NULL;
|
||||||
|
|
||||||
static ConfigParam * newConfigParam(char * value, int line) {
|
static ConfigParam *newConfigParam(char *value, int line)
|
||||||
ConfigParam * ret = malloc(sizeof(ConfigParam));
|
{
|
||||||
|
ConfigParam *ret = malloc(sizeof(ConfigParam));
|
||||||
|
|
||||||
if(!value) ret->value = NULL;
|
if (!value)
|
||||||
else ret->value = strdup(value);
|
ret->value = NULL;
|
||||||
|
else
|
||||||
|
ret->value = strdup(value);
|
||||||
|
|
||||||
ret->line = line;
|
ret->line = line;
|
||||||
|
|
||||||
@ -63,46 +66,55 @@ static ConfigParam * newConfigParam(char * value, int line) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeConfigParam(ConfigParam * param) {
|
static void freeConfigParam(ConfigParam * param)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(param->value) free(param->value);
|
if (param->value)
|
||||||
|
free(param->value);
|
||||||
|
|
||||||
for(i=0; i<param->numberOfBlockParams; i++) {
|
for (i = 0; i < param->numberOfBlockParams; i++) {
|
||||||
if(param->blockParams[i].name) {
|
if (param->blockParams[i].name) {
|
||||||
free(param->blockParams[i].name);
|
free(param->blockParams[i].name);
|
||||||
}
|
}
|
||||||
if(param->blockParams[i].value) {
|
if (param->blockParams[i].value) {
|
||||||
free(param->blockParams[i].value);
|
free(param->blockParams[i].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(param->numberOfBlockParams) free(param->blockParams);
|
if (param->numberOfBlockParams)
|
||||||
|
free(param->blockParams);
|
||||||
|
|
||||||
free(param);
|
free(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigEntry * newConfigEntry(int repeatable, int block) {
|
ConfigEntry *newConfigEntry(int repeatable, int block)
|
||||||
ConfigEntry * ret = malloc(sizeof(ConfigEntry));
|
{
|
||||||
|
ConfigEntry *ret = malloc(sizeof(ConfigEntry));
|
||||||
|
|
||||||
ret->mask = 0;
|
ret->mask = 0;
|
||||||
ret->configParamList = makeList((ListFreeDataFunc *)freeConfigParam, 1);
|
ret->configParamList =
|
||||||
|
makeList((ListFreeDataFunc *) freeConfigParam, 1);
|
||||||
|
|
||||||
if(repeatable) ret->mask |= CONF_REPEATABLE_MASK;
|
if (repeatable)
|
||||||
if(block) ret->mask |= CONF_BLOCK_MASK;
|
ret->mask |= CONF_REPEATABLE_MASK;
|
||||||
|
if (block)
|
||||||
|
ret->mask |= CONF_BLOCK_MASK;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeConfigEntry(ConfigEntry * entry) {
|
void freeConfigEntry(ConfigEntry * entry)
|
||||||
|
{
|
||||||
freeList(entry->configParamList);
|
freeList(entry->configParamList);
|
||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerConfigParam(char * name, int repeatable, int block) {
|
static void registerConfigParam(char *name, int repeatable, int block)
|
||||||
ConfigEntry * entry;
|
{
|
||||||
|
ConfigEntry *entry;
|
||||||
|
|
||||||
if(findInList(configEntriesList, name, NULL)) {
|
if (findInList(configEntriesList, name, NULL)) {
|
||||||
ERROR("config parameter \"%s\" already registered\n", name);
|
ERROR("config parameter \"%s\" already registered\n", name);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -112,12 +124,14 @@ static void registerConfigParam(char * name, int repeatable, int block) {
|
|||||||
insertInList(configEntriesList, name, entry);
|
insertInList(configEntriesList, name, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishConf(void) {
|
void finishConf(void)
|
||||||
|
{
|
||||||
freeList(configEntriesList);
|
freeList(configEntriesList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initConf(void) {
|
void initConf(void)
|
||||||
configEntriesList = makeList((ListFreeDataFunc *)freeConfigEntry, 1);
|
{
|
||||||
|
configEntriesList = makeList((ListFreeDataFunc *) freeConfigEntry, 1);
|
||||||
|
|
||||||
/* registerConfigParam(name, repeatable, block); */
|
/* registerConfigParam(name, repeatable, block); */
|
||||||
registerConfigParam(CONF_PORT, 0, 0);
|
registerConfigParam(CONF_PORT, 0, 0);
|
||||||
@ -159,61 +173,63 @@ void initConf(void) {
|
|||||||
registerConfigParam(CONF_ID3V1_ENCODING, 0, 0);
|
registerConfigParam(CONF_ID3V1_ENCODING, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addBlockParam(ConfigParam * param, char * name, char * value,
|
static void addBlockParam(ConfigParam * param, char *name, char *value,
|
||||||
int line)
|
int line)
|
||||||
{
|
{
|
||||||
param->numberOfBlockParams++;
|
param->numberOfBlockParams++;
|
||||||
|
|
||||||
param->blockParams = realloc(param->blockParams,
|
param->blockParams = realloc(param->blockParams,
|
||||||
param->numberOfBlockParams*sizeof(BlockParam));
|
param->numberOfBlockParams *
|
||||||
|
sizeof(BlockParam));
|
||||||
|
|
||||||
param->blockParams[param->numberOfBlockParams-1].name = strdup(name);
|
param->blockParams[param->numberOfBlockParams - 1].name = strdup(name);
|
||||||
param->blockParams[param->numberOfBlockParams-1].value = strdup(value);
|
param->blockParams[param->numberOfBlockParams - 1].value =
|
||||||
param->blockParams[param->numberOfBlockParams-1].line = line;
|
strdup(value);
|
||||||
|
param->blockParams[param->numberOfBlockParams - 1].line = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConfigParam * readConfigBlock(FILE * fp, int * count, char * string) {
|
static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
|
||||||
ConfigParam * ret = newConfigParam(NULL, *count);
|
{
|
||||||
|
ConfigParam *ret = newConfigParam(NULL, *count);
|
||||||
|
|
||||||
char ** array;
|
char **array;
|
||||||
int i;
|
int i;
|
||||||
int numberOfArgs;
|
int numberOfArgs;
|
||||||
int argsMinusComment;
|
int argsMinusComment;
|
||||||
|
|
||||||
while(myFgets(string, MAX_STRING_SIZE ,fp)) {
|
while (myFgets(string, MAX_STRING_SIZE, fp)) {
|
||||||
(*count)++;
|
(*count)++;
|
||||||
|
|
||||||
numberOfArgs = buffer2array(string, &array);
|
numberOfArgs = buffer2array(string, &array);
|
||||||
|
|
||||||
for(i=0; i<numberOfArgs; i++) {
|
for (i = 0; i < numberOfArgs; i++) {
|
||||||
if(array[i][0] == CONF_COMMENT) break;
|
if (array[i][0] == CONF_COMMENT)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
argsMinusComment = i;
|
argsMinusComment = i;
|
||||||
|
|
||||||
if(0 == argsMinusComment) {
|
if (0 == argsMinusComment) {
|
||||||
freeArgArray(array, numberOfArgs);
|
freeArgArray(array, numberOfArgs);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(1 == argsMinusComment &&
|
if (1 == argsMinusComment &&
|
||||||
0 == strcmp(array[0], CONF_BLOCK_END))
|
0 == strcmp(array[0], CONF_BLOCK_END)) {
|
||||||
{
|
|
||||||
freeArgArray(array, numberOfArgs);
|
freeArgArray(array, numberOfArgs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(2 != argsMinusComment) {
|
if (2 != argsMinusComment) {
|
||||||
ERROR("improperly formatted config file at line %i:"
|
ERROR("improperly formatted config file at line %i:"
|
||||||
" %s\n", *count, string);
|
" %s\n", *count, string);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 == strcmp(array[0], CONF_BLOCK_BEGIN) ||
|
if (0 == strcmp(array[0], CONF_BLOCK_BEGIN) ||
|
||||||
0 == strcmp(array[1], CONF_BLOCK_BEGIN) ||
|
0 == strcmp(array[1], CONF_BLOCK_BEGIN) ||
|
||||||
0 == strcmp(array[0], CONF_BLOCK_END) ||
|
0 == strcmp(array[0], CONF_BLOCK_END) ||
|
||||||
0 == strcmp(array[1], CONF_BLOCK_END))
|
0 == strcmp(array[1], CONF_BLOCK_END)) {
|
||||||
{
|
|
||||||
ERROR("improperly formatted config file at line %i:"
|
ERROR("improperly formatted config file at line %i:"
|
||||||
" %s\n", count, string);
|
" %s\n", count, string);
|
||||||
ERROR("in block begining at line %i\n", ret->line);
|
ERROR("in block begining at line %i\n", ret->line);
|
||||||
@ -228,47 +244,49 @@ static ConfigParam * readConfigBlock(FILE * fp, int * count, char * string) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void readConf(char * file) {
|
void readConf(char *file)
|
||||||
FILE * fp;
|
{
|
||||||
char string[MAX_STRING_SIZE+1];
|
FILE *fp;
|
||||||
char ** array;
|
char string[MAX_STRING_SIZE + 1];
|
||||||
|
char **array;
|
||||||
int i;
|
int i;
|
||||||
int numberOfArgs;
|
int numberOfArgs;
|
||||||
int argsMinusComment;
|
int argsMinusComment;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
ConfigEntry * entry;
|
ConfigEntry *entry;
|
||||||
void * voidPtr;
|
void *voidPtr;
|
||||||
ConfigParam * param;
|
ConfigParam *param;
|
||||||
|
|
||||||
if(!(fp=fopen(file,"r"))) {
|
if (!(fp = fopen(file, "r"))) {
|
||||||
ERROR("problems opening file %s for reading: %s\n", file,
|
ERROR("problems opening file %s for reading: %s\n", file,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(myFgets(string, MAX_STRING_SIZE, fp)) {
|
while (myFgets(string, MAX_STRING_SIZE, fp)) {
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
numberOfArgs = buffer2array(string, &array);
|
numberOfArgs = buffer2array(string, &array);
|
||||||
|
|
||||||
for(i=0; i<numberOfArgs; i++) {
|
for (i = 0; i < numberOfArgs; i++) {
|
||||||
if(array[i][0] == CONF_COMMENT) break;
|
if (array[i][0] == CONF_COMMENT)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
argsMinusComment = i;
|
argsMinusComment = i;
|
||||||
|
|
||||||
if(0 == argsMinusComment) {
|
if (0 == argsMinusComment) {
|
||||||
freeArgArray(array, numberOfArgs);
|
freeArgArray(array, numberOfArgs);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(2 != argsMinusComment) {
|
if (2 != argsMinusComment) {
|
||||||
ERROR("improperly formatted config file at line %i:"
|
ERROR("improperly formatted config file at line %i:"
|
||||||
" %s\n", count, string);
|
" %s\n", count, string);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!findInList(configEntriesList, array[0], &voidPtr)) {
|
if (!findInList(configEntriesList, array[0], &voidPtr)) {
|
||||||
ERROR("unrecognized parameter in config file at line "
|
ERROR("unrecognized parameter in config file at line "
|
||||||
"%i: %s\n", count, string);
|
"%i: %s\n", count, string);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -276,25 +294,25 @@ void readConf(char * file) {
|
|||||||
|
|
||||||
entry = (ConfigEntry *) voidPtr;
|
entry = (ConfigEntry *) voidPtr;
|
||||||
|
|
||||||
if( !(entry->mask & CONF_REPEATABLE_MASK) &&
|
if (!(entry->mask & CONF_REPEATABLE_MASK) &&
|
||||||
entry->configParamList->numberOfNodes)
|
entry->configParamList->numberOfNodes) {
|
||||||
{
|
|
||||||
param = entry->configParamList->firstNode->data;
|
param = entry->configParamList->firstNode->data;
|
||||||
ERROR("config parameter \"%s\" is first defined on line "
|
ERROR
|
||||||
"%i and redefined on line %i\n",
|
("config parameter \"%s\" is first defined on line "
|
||||||
array[0], param->line, count);
|
"%i and redefined on line %i\n", array[0],
|
||||||
|
param->line, count);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(entry->mask & CONF_BLOCK_MASK) {
|
if (entry->mask & CONF_BLOCK_MASK) {
|
||||||
if(0 != strcmp(array[1], CONF_BLOCK_BEGIN)) {
|
if (0 != strcmp(array[1], CONF_BLOCK_BEGIN)) {
|
||||||
ERROR("improperly formatted config file at "
|
ERROR("improperly formatted config file at "
|
||||||
"line %i: %s\n", count, string);
|
"line %i: %s\n", count, string);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
param = readConfigBlock(fp, &count, string);
|
param = readConfigBlock(fp, &count, string);
|
||||||
}
|
} else
|
||||||
else param = newConfigParam(array[1], count);
|
param = newConfigParam(array[1], count);
|
||||||
|
|
||||||
insertInListWithoutKey(entry->configParamList, param);
|
insertInListWithoutKey(entry->configParamList, param);
|
||||||
|
|
||||||
@ -303,120 +321,129 @@ void readConf(char * file) {
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigParam * getNextConfigParam(char * name, ConfigParam * last) {
|
ConfigParam *getNextConfigParam(char *name, ConfigParam * last)
|
||||||
void * voidPtr;
|
{
|
||||||
ConfigEntry * entry;
|
void *voidPtr;
|
||||||
ListNode * node;
|
ConfigEntry *entry;
|
||||||
ConfigParam * param;
|
ListNode *node;
|
||||||
|
ConfigParam *param;
|
||||||
|
|
||||||
if(!findInList(configEntriesList, name, &voidPtr)) return NULL;
|
if (!findInList(configEntriesList, name, &voidPtr))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
entry = voidPtr;
|
entry = voidPtr;
|
||||||
|
|
||||||
node = entry->configParamList->firstNode;
|
node = entry->configParamList->firstNode;
|
||||||
|
|
||||||
if(last) {
|
if (last) {
|
||||||
while(node!=NULL) {
|
while (node != NULL) {
|
||||||
param = node->data;
|
param = node->data;
|
||||||
node = node->nextNode;
|
node = node->nextNode;
|
||||||
if(param == last) break;
|
if (param == last)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node == NULL) return NULL;
|
if (node == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
param = node->data;
|
param = node->data;
|
||||||
|
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * getConfigParamValue(char * name) {
|
char *getConfigParamValue(char *name)
|
||||||
ConfigParam * param = getConfigParam(name);
|
{
|
||||||
|
ConfigParam *param = getConfigParam(name);
|
||||||
|
|
||||||
if(!param) return NULL;
|
if (!param)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return param->value;
|
return param->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockParam * getBlockParam(ConfigParam * param, char * name) {
|
BlockParam *getBlockParam(ConfigParam * param, char *name)
|
||||||
BlockParam * ret = NULL;
|
{
|
||||||
|
BlockParam *ret = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < param->numberOfBlockParams; i++) {
|
for (i = 0; i < param->numberOfBlockParams; i++) {
|
||||||
if(0 == strcmp(name, param->blockParams[i].name)) {
|
if (0 == strcmp(name, param->blockParams[i].name)) {
|
||||||
if(ret) {
|
if (ret) {
|
||||||
ERROR("\"%s\" first defined on line %i, and "
|
ERROR("\"%s\" first defined on line %i, and "
|
||||||
"redefined on line %i\n", name,
|
"redefined on line %i\n", name,
|
||||||
ret->line, param->blockParams[i].line);
|
ret->line, param->blockParams[i].line);
|
||||||
}
|
}
|
||||||
ret = param->blockParams+i;
|
ret = param->blockParams + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigParam * parseConfigFilePath(char * name, int force) {
|
ConfigParam *parseConfigFilePath(char *name, int force)
|
||||||
ConfigParam * param = getConfigParam(name);
|
{
|
||||||
char * path;
|
ConfigParam *param = getConfigParam(name);
|
||||||
|
char *path;
|
||||||
|
|
||||||
if(!param && force) {
|
if (!param && force) {
|
||||||
ERROR("config parameter \"%s\" not found\n", name);
|
ERROR("config parameter \"%s\" not found\n", name);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!param) return NULL;
|
if (!param)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
path = param->value;
|
path = param->value;
|
||||||
|
|
||||||
if(path[0] != '/' && path[0] != '~') {
|
if (path[0] != '/' && path[0] != '~') {
|
||||||
ERROR("\"%s\" is not an absolute path at line %i\n",
|
ERROR("\"%s\" is not an absolute path at line %i\n",
|
||||||
param->value, param->line);
|
param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
/* Parse ~ in path */
|
/* Parse ~ in path */
|
||||||
else if(path[0] == '~') {
|
else if (path[0] == '~') {
|
||||||
struct passwd * pwd = NULL;
|
struct passwd *pwd = NULL;
|
||||||
char * newPath;
|
char *newPath;
|
||||||
int pos = 1;
|
int pos = 1;
|
||||||
if(path[1]=='/' || path[1] == '\0') {
|
if (path[1] == '/' || path[1] == '\0') {
|
||||||
ConfigParam * userParam = getConfigParam(CONF_USER);
|
ConfigParam *userParam = getConfigParam(CONF_USER);
|
||||||
|
|
||||||
if(userParam) {
|
if (userParam) {
|
||||||
pwd = getpwnam(userParam->value);
|
pwd = getpwnam(userParam->value);
|
||||||
if(!pwd) {
|
if (!pwd) {
|
||||||
ERROR("no such user %s at line %i\n",
|
ERROR("no such user %s at line %i\n",
|
||||||
userParam->value,
|
userParam->value,
|
||||||
userParam->line);
|
userParam->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
uid_t uid = geteuid();
|
uid_t uid = geteuid();
|
||||||
if((pwd = getpwuid(uid)) == NULL) {
|
if ((pwd = getpwuid(uid)) == NULL) {
|
||||||
ERROR("problems getting passwd entry "
|
ERROR("problems getting passwd entry "
|
||||||
"for current user\n");
|
"for current user\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int foundSlash = 0;
|
int foundSlash = 0;
|
||||||
char * ch = path+1;
|
char *ch = path + 1;
|
||||||
for(;*ch!='\0' && *ch!='/';ch++);
|
for (; *ch != '\0' && *ch != '/'; ch++) ;
|
||||||
if(*ch=='/') foundSlash = 1;
|
if (*ch == '/')
|
||||||
* ch = '\0';
|
foundSlash = 1;
|
||||||
pos+= ch-path-1;
|
*ch = '\0';
|
||||||
if((pwd = getpwnam(path+1)) == NULL) {
|
pos += ch - path - 1;
|
||||||
|
if ((pwd = getpwnam(path + 1)) == NULL) {
|
||||||
ERROR("user \"%s\" not found at line %i\n",
|
ERROR("user \"%s\" not found at line %i\n",
|
||||||
path+1, param->line);
|
path + 1, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if(foundSlash) *ch = '/';
|
if (foundSlash)
|
||||||
|
*ch = '/';
|
||||||
}
|
}
|
||||||
newPath = malloc(strlen(pwd->pw_dir)+strlen(path+pos)+1);
|
newPath = malloc(strlen(pwd->pw_dir) + strlen(path + pos) + 1);
|
||||||
strcpy(newPath, pwd->pw_dir);
|
strcpy(newPath, pwd->pw_dir);
|
||||||
strcat(newPath, path+pos);
|
strcat(newPath, path + pos);
|
||||||
free(param->value);
|
free(param->value);
|
||||||
param->value = newPath;
|
param->value = newPath;
|
||||||
}
|
}
|
||||||
|
18
src/conf.h
18
src/conf.h
@ -60,33 +60,33 @@
|
|||||||
#define CONF_ID3V1_ENCODING "id3v1_encoding"
|
#define CONF_ID3V1_ENCODING "id3v1_encoding"
|
||||||
|
|
||||||
typedef struct _BlockParam {
|
typedef struct _BlockParam {
|
||||||
char * name;
|
char *name;
|
||||||
char * value;
|
char *value;
|
||||||
int line;
|
int line;
|
||||||
} BlockParam;
|
} BlockParam;
|
||||||
|
|
||||||
typedef struct _ConfigParam {
|
typedef struct _ConfigParam {
|
||||||
char * value;
|
char *value;
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
BlockParam * blockParams;
|
BlockParam *blockParams;
|
||||||
int numberOfBlockParams;
|
int numberOfBlockParams;
|
||||||
} ConfigParam;
|
} ConfigParam;
|
||||||
|
|
||||||
void initConf();
|
void initConf();
|
||||||
void finishConf();
|
void finishConf();
|
||||||
|
|
||||||
void readConf(char * file);
|
void readConf(char *file);
|
||||||
|
|
||||||
/* don't free the returned value
|
/* don't free the returned value
|
||||||
set _last_ to NULL to get first entry */
|
set _last_ to NULL to get first entry */
|
||||||
ConfigParam * getNextConfigParam(char * name, ConfigParam * last);
|
ConfigParam *getNextConfigParam(char *name, ConfigParam * last);
|
||||||
|
|
||||||
#define getConfigParam(name) getNextConfigParam(name, NULL)
|
#define getConfigParam(name) getNextConfigParam(name, NULL)
|
||||||
|
|
||||||
char * getConfigParamValue(char * name);
|
char *getConfigParamValue(char *name);
|
||||||
|
|
||||||
BlockParam * getBlockParam(ConfigParam * param, char * name);
|
BlockParam *getBlockParam(ConfigParam * param, char *name);
|
||||||
|
|
||||||
ConfigParam * parseConfigFilePath(char * name, int force);
|
ConfigParam *parseConfigFilePath(char *name, int force);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
276
src/dbUtils.c
276
src/dbUtils.c
@ -31,52 +31,54 @@
|
|||||||
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
|
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
|
||||||
#define LOCATE_TAG_ANY_KEY "any"
|
#define LOCATE_TAG_ANY_KEY "any"
|
||||||
|
|
||||||
|
|
||||||
typedef struct _ListCommandItem {
|
typedef struct _ListCommandItem {
|
||||||
mpd_sint8 tagType;
|
mpd_sint8 tagType;
|
||||||
int numConditionals;
|
int numConditionals;
|
||||||
LocateTagItem * conditionals;
|
LocateTagItem *conditionals;
|
||||||
} ListCommandItem;
|
} ListCommandItem;
|
||||||
|
|
||||||
typedef struct _LocateTagItemArray {
|
typedef struct _LocateTagItemArray {
|
||||||
int numItems;
|
int numItems;
|
||||||
LocateTagItem * items;
|
LocateTagItem *items;
|
||||||
} LocateTagItemArray;
|
} LocateTagItemArray;
|
||||||
|
|
||||||
int getLocateTagItemType(char * str) {
|
int getLocateTagItemType(char *str)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(0 == strcasecmp(str, LOCATE_TAG_FILE_KEY)) {
|
if (0 == strcasecmp(str, LOCATE_TAG_FILE_KEY)) {
|
||||||
return LOCATE_TAG_FILE_TYPE;
|
return LOCATE_TAG_FILE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 == strcasecmp(str, LOCATE_TAG_ANY_KEY)) {
|
if (0 == strcasecmp(str, LOCATE_TAG_ANY_KEY)) {
|
||||||
return LOCATE_TAG_ANY_TYPE;
|
return LOCATE_TAG_ANY_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
||||||
if(0 == strcasecmp(str, mpdTagItemKeys[i])) return i;
|
if (0 == strcasecmp(str, mpdTagItemKeys[i]))
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int initLocateTagItem(LocateTagItem * item, char * typeStr,
|
static int initLocateTagItem(LocateTagItem * item, char *typeStr, char *needle)
|
||||||
char * needle)
|
|
||||||
{
|
{
|
||||||
item->tagType = getLocateTagItemType(typeStr);
|
item->tagType = getLocateTagItemType(typeStr);
|
||||||
|
|
||||||
if(item->tagType < 0) return -1;
|
if (item->tagType < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
item->needle = strdup(needle);
|
item->needle = strdup(needle);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocateTagItem * newLocateTagItem(char * typeStr, char * needle) {
|
LocateTagItem *newLocateTagItem(char *typeStr, char *needle)
|
||||||
LocateTagItem * ret = malloc(sizeof(LocateTagItem));
|
{
|
||||||
|
LocateTagItem *ret = malloc(sizeof(LocateTagItem));
|
||||||
|
|
||||||
if(initLocateTagItem(ret, typeStr, needle) < 0) {
|
if (initLocateTagItem(ret, typeStr, needle) < 0) {
|
||||||
free(ret);
|
free(ret);
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
}
|
}
|
||||||
@ -84,36 +86,40 @@ LocateTagItem * newLocateTagItem(char * typeStr, char * needle) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeLocateTagItemArray(int count, LocateTagItem * array) {
|
void freeLocateTagItemArray(int count, LocateTagItem * array)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < count; i++) free(array[i].needle);
|
for (i = 0; i < count; i++)
|
||||||
|
free(array[i].needle);
|
||||||
|
|
||||||
free(array);
|
free(array);
|
||||||
}
|
}
|
||||||
|
|
||||||
int newLocateTagItemArrayFromArgArray(char * argArray[],
|
int newLocateTagItemArrayFromArgArray(char *argArray[],
|
||||||
int numArgs,
|
int numArgs, LocateTagItem ** arrayRet)
|
||||||
LocateTagItem ** arrayRet)
|
|
||||||
{
|
{
|
||||||
int i,j;
|
int i, j;
|
||||||
LocateTagItem * item;
|
LocateTagItem *item;
|
||||||
|
|
||||||
if(numArgs == 0) return 0;
|
if (numArgs == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if(numArgs%2 != 0) return -1;
|
if (numArgs % 2 != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
*arrayRet = malloc(sizeof(LocateTagItem)*numArgs/2);
|
*arrayRet = malloc(sizeof(LocateTagItem) * numArgs / 2);
|
||||||
|
|
||||||
for(i = 0, item = *arrayRet; i < numArgs/2; i++, item++) {
|
for (i = 0, item = *arrayRet; i < numArgs / 2; i++, item++) {
|
||||||
if(initLocateTagItem(item, argArray[i*2], argArray[i*2+1]) < 0)
|
if (initLocateTagItem
|
||||||
|
(item, argArray[i * 2], argArray[i * 2 + 1]) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
return numArgs/2;
|
return numArgs / 2;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
for(j = 0; j < i; j++) {
|
for (j = 0; j < i; j++) {
|
||||||
free((*arrayRet)[j].needle);
|
free((*arrayRet)[j].needle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,70 +128,78 @@ fail:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeLocateTagItem(LocateTagItem * item) {
|
void freeLocateTagItem(LocateTagItem * item)
|
||||||
|
{
|
||||||
free(item->needle);
|
free(item->needle);
|
||||||
free(item);
|
free(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int countSongsInDirectory(FILE * fp, Directory * directory, void * data) {
|
static int countSongsInDirectory(FILE * fp, Directory * directory, void *data)
|
||||||
int * count = (int *)data;
|
{
|
||||||
|
int *count = (int *)data;
|
||||||
|
|
||||||
*count+=directory->songs->numberOfNodes;
|
*count += directory->songs->numberOfNodes;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int printDirectoryInDirectory(FILE * fp, Directory * directory, void * data) {
|
static int printDirectoryInDirectory(FILE * fp, Directory * directory,
|
||||||
if(directory->path) {
|
void *data)
|
||||||
myfprintf(fp,"directory: %s\n", getDirectoryPath(directory));
|
{
|
||||||
|
if (directory->path) {
|
||||||
|
myfprintf(fp, "directory: %s\n", getDirectoryPath(directory));
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int printSongInDirectory(FILE * fp, Song * song, void * data) {
|
static int printSongInDirectory(FILE * fp, Song * song, void *data)
|
||||||
|
{
|
||||||
printSongUrl(fp, song);
|
printSongUrl(fp, song);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int strstrSearchTag(Song * song, int type, char * str) {
|
static int strstrSearchTag(Song * song, int type, char *str)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
char * dup;
|
char *dup;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if(type == LOCATE_TAG_FILE_TYPE || type == LOCATE_TAG_ANY_TYPE) {
|
if (type == LOCATE_TAG_FILE_TYPE || type == LOCATE_TAG_ANY_TYPE) {
|
||||||
dup = strDupToUpper(getSongUrl(song));
|
dup = strDupToUpper(getSongUrl(song));
|
||||||
if(strstr(dup, str)) ret = 1;
|
if (strstr(dup, str))
|
||||||
|
ret = 1;
|
||||||
free(dup);
|
free(dup);
|
||||||
if (ret == 1 || type == LOCATE_TAG_FILE_TYPE) {
|
if (ret == 1 || type == LOCATE_TAG_FILE_TYPE) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!song->tag) return 0;
|
if (!song->tag)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for(i = 0; i < song->tag->numOfItems && !ret; i++) {
|
for (i = 0; i < song->tag->numOfItems && !ret; i++) {
|
||||||
if(type != LOCATE_TAG_ANY_TYPE &&
|
if (type != LOCATE_TAG_ANY_TYPE &&
|
||||||
song->tag->items[i].type != type)
|
song->tag->items[i].type != type) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
dup = strDupToUpper(song->tag->items[i].value);
|
dup = strDupToUpper(song->tag->items[i].value);
|
||||||
if(strstr(dup, str)) ret = 1;
|
if (strstr(dup, str))
|
||||||
|
ret = 1;
|
||||||
free(dup);
|
free(dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int searchInDirectory(FILE * fp, Song * song, void * data) {
|
static int searchInDirectory(FILE * fp, Song * song, void *data)
|
||||||
LocateTagItemArray * array = data;
|
{
|
||||||
|
LocateTagItemArray *array = data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < array->numItems; i++) {
|
for (i = 0; i < array->numItems; i++) {
|
||||||
if(!strstrSearchTag(song, array->items[i].tagType,
|
if (!strstrSearchTag(song, array->items[i].tagType,
|
||||||
array->items[i].needle))
|
array->items[i].needle)) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,16 +209,15 @@ static int searchInDirectory(FILE * fp, Song * song, void * data) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int searchForSongsIn(FILE * fp, char * name, int numItems,
|
int searchForSongsIn(FILE * fp, char *name, int numItems, LocateTagItem * items)
|
||||||
LocateTagItem * items)
|
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
char ** originalNeedles = malloc(numItems*sizeof(char *));
|
char **originalNeedles = malloc(numItems * sizeof(char *));
|
||||||
LocateTagItemArray array;
|
LocateTagItemArray array;
|
||||||
|
|
||||||
for(i = 0; i < numItems; i++) {
|
for (i = 0; i < numItems; i++) {
|
||||||
originalNeedles[i] = items[i].needle;
|
originalNeedles[i] = items[i].needle;
|
||||||
items[i].needle = strDupToUpper(originalNeedles[i]);
|
items[i].needle = strDupToUpper(originalNeedles[i]);
|
||||||
}
|
}
|
||||||
@ -212,9 +225,9 @@ int searchForSongsIn(FILE * fp, char * name, int numItems,
|
|||||||
array.numItems = numItems;
|
array.numItems = numItems;
|
||||||
array.items = items;
|
array.items = items;
|
||||||
|
|
||||||
ret = traverseAllIn(fp,name,searchInDirectory, NULL, &array);
|
ret = traverseAllIn(fp, name, searchInDirectory, NULL, &array);
|
||||||
|
|
||||||
for(i = 0; i < numItems; i++) {
|
for (i = 0; i < numItems; i++) {
|
||||||
free(items[i].needle);
|
free(items[i].needle);
|
||||||
items[i].needle = originalNeedles[i];
|
items[i].needle = originalNeedles[i];
|
||||||
}
|
}
|
||||||
@ -224,32 +237,37 @@ int searchForSongsIn(FILE * fp, char * name, int numItems,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tagItemFoundAndMatches(Song * song, int type, char * str) {
|
static int tagItemFoundAndMatches(Song * song, int type, char *str)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(type == LOCATE_TAG_FILE_TYPE) {
|
if (type == LOCATE_TAG_FILE_TYPE) {
|
||||||
if(0 == strcmp(str, getSongUrl(song))) return 1;
|
if (0 == strcmp(str, getSongUrl(song)))
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!song->tag) return 0;
|
if (!song->tag)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for(i = 0; i < song->tag->numOfItems; i++) {
|
for (i = 0; i < song->tag->numOfItems; i++) {
|
||||||
if(song->tag->items[i].type != type) continue;
|
if (song->tag->items[i].type != type)
|
||||||
|
continue;
|
||||||
|
|
||||||
if(0 == strcmp(str, song->tag->items[i].value)) return 1;
|
if (0 == strcmp(str, song->tag->items[i].value))
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int findInDirectory(FILE * fp, Song * song, void * data) {
|
static int findInDirectory(FILE * fp, Song * song, void *data)
|
||||||
LocateTagItemArray * array = data;
|
{
|
||||||
|
LocateTagItemArray *array = data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < array->numItems; i++) {
|
for (i = 0; i < array->numItems; i++) {
|
||||||
if(!tagItemFoundAndMatches(song, array->items[i].tagType,
|
if (!tagItemFoundAndMatches(song, array->items[i].tagType,
|
||||||
array->items[i].needle))
|
array->items[i].needle)) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,67 +277,77 @@ static int findInDirectory(FILE * fp, Song * song, void * data) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int findSongsIn(FILE * fp, char * name, int numItems, LocateTagItem * items) {
|
int findSongsIn(FILE * fp, char *name, int numItems, LocateTagItem * items)
|
||||||
|
{
|
||||||
LocateTagItemArray array;
|
LocateTagItemArray array;
|
||||||
|
|
||||||
array.numItems = numItems;
|
array.numItems = numItems;
|
||||||
array.items = items;
|
array.items = items;
|
||||||
|
|
||||||
return traverseAllIn(fp, name, findInDirectory, NULL,
|
return traverseAllIn(fp, name, findInDirectory, NULL, (void *)&array);
|
||||||
(void *)&array);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int printAllIn(FILE * fp, char * name) {
|
int printAllIn(FILE * fp, char *name)
|
||||||
return traverseAllIn(fp,name,printSongInDirectory,
|
{
|
||||||
printDirectoryInDirectory,NULL);
|
return traverseAllIn(fp, name, printSongInDirectory,
|
||||||
|
printDirectoryInDirectory, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int directoryAddSongToPlaylist(FILE * fp, Song * song, void * data) {
|
static int directoryAddSongToPlaylist(FILE * fp, Song * song, void *data)
|
||||||
|
{
|
||||||
return addSongToPlaylist(fp, song, 0);
|
return addSongToPlaylist(fp, song, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int addAllIn(FILE * fp, char * name) {
|
int addAllIn(FILE * fp, char *name)
|
||||||
return traverseAllIn(fp,name,directoryAddSongToPlaylist,NULL,NULL);
|
{
|
||||||
|
return traverseAllIn(fp, name, directoryAddSongToPlaylist, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int directoryPrintSongInfo(FILE * fp, Song * song, void * data) {
|
static int directoryPrintSongInfo(FILE * fp, Song * song, void *data)
|
||||||
return printSongInfo(fp,song);
|
{
|
||||||
|
return printSongInfo(fp, song);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sumSongTime(FILE * fp, Song * song, void * data) {
|
static int sumSongTime(FILE * fp, Song * song, void *data)
|
||||||
unsigned long * time = (unsigned long *)data;
|
{
|
||||||
|
unsigned long *time = (unsigned long *)data;
|
||||||
|
|
||||||
if(song->tag && song->tag->time>=0) *time+=song->tag->time;
|
if (song->tag && song->tag->time >= 0)
|
||||||
|
*time += song->tag->time;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int printInfoForAllIn(FILE * fp, char * name) {
|
int printInfoForAllIn(FILE * fp, char *name)
|
||||||
return traverseAllIn(fp,name,directoryPrintSongInfo,printDirectoryInDirectory,NULL);
|
{
|
||||||
|
return traverseAllIn(fp, name, directoryPrintSongInfo,
|
||||||
|
printDirectoryInDirectory, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int countSongsIn(FILE * fp, char * name) {
|
int countSongsIn(FILE * fp, char *name)
|
||||||
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
void * ptr = (void *)&count;
|
void *ptr = (void *)&count;
|
||||||
|
|
||||||
traverseAllIn(fp,name,NULL,countSongsInDirectory,ptr);
|
traverseAllIn(fp, name, NULL, countSongsInDirectory, ptr);
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long sumSongTimesIn(FILE * fp, char * name) {
|
unsigned long sumSongTimesIn(FILE * fp, char *name)
|
||||||
|
{
|
||||||
unsigned long dbPlayTime = 0;
|
unsigned long dbPlayTime = 0;
|
||||||
void * ptr = (void *)&dbPlayTime;
|
void *ptr = (void *)&dbPlayTime;
|
||||||
|
|
||||||
traverseAllIn(fp,name,sumSongTime,NULL,ptr);
|
traverseAllIn(fp, name, sumSongTime, NULL, ptr);
|
||||||
|
|
||||||
return dbPlayTime;
|
return dbPlayTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ListCommandItem * newListCommandItem(int tagType, int numConditionals,
|
static ListCommandItem *newListCommandItem(int tagType, int numConditionals,
|
||||||
LocateTagItem * conditionals)
|
LocateTagItem * conditionals)
|
||||||
{
|
{
|
||||||
ListCommandItem * item = malloc(sizeof(ListCommandItem));
|
ListCommandItem *item = malloc(sizeof(ListCommandItem));
|
||||||
|
|
||||||
item->tagType = tagType;
|
item->tagType = tagType;
|
||||||
item->numConditionals = numConditionals;
|
item->numConditionals = numConditionals;
|
||||||
@ -328,36 +356,39 @@ static ListCommandItem * newListCommandItem(int tagType, int numConditionals,
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeListCommandItem(ListCommandItem * item) {
|
static void freeListCommandItem(ListCommandItem * item)
|
||||||
|
{
|
||||||
free(item);
|
free(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void visitTag(FILE * fp, Song * song, int tagType) {
|
static void visitTag(FILE * fp, Song * song, int tagType)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
MpdTag * tag = song->tag;
|
MpdTag *tag = song->tag;
|
||||||
|
|
||||||
if(tagType == LOCATE_TAG_FILE_TYPE) {
|
if (tagType == LOCATE_TAG_FILE_TYPE) {
|
||||||
printSongUrl(fp, song);
|
printSongUrl(fp, song);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!tag) return;
|
if (!tag)
|
||||||
|
return;
|
||||||
|
|
||||||
for(i = 0; i < tag->numOfItems; i++) {
|
for (i = 0; i < tag->numOfItems; i++) {
|
||||||
if(tag->items[i].type == tagType) {
|
if (tag->items[i].type == tagType) {
|
||||||
visitInTagTracker(tagType, tag->items[i].value);
|
visitInTagTracker(tagType, tag->items[i].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int listUniqueTagsInDirectory(FILE * fp, Song * song, void * data) {
|
static int listUniqueTagsInDirectory(FILE * fp, Song * song, void *data)
|
||||||
ListCommandItem * item = data;
|
{
|
||||||
|
ListCommandItem *item = data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < item->numConditionals; i++) {
|
for (i = 0; i < item->numConditionals; i++) {
|
||||||
if(!tagItemFoundAndMatches(song, item->conditionals[i].tagType,
|
if (!tagItemFoundAndMatches(song, item->conditionals[i].tagType,
|
||||||
item->conditionals[i].needle))
|
item->conditionals[i].needle)) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -371,17 +402,17 @@ int listAllUniqueTags(FILE * fp, int type, int numConditionals,
|
|||||||
LocateTagItem * conditionals)
|
LocateTagItem * conditionals)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
ListCommandItem * item = newListCommandItem(type, numConditionals,
|
ListCommandItem *item = newListCommandItem(type, numConditionals,
|
||||||
conditionals);
|
conditionals);
|
||||||
|
|
||||||
if(type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
|
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
|
||||||
resetVisitedFlagsInTagTracker(type);
|
resetVisitedFlagsInTagTracker(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = traverseAllIn(fp, NULL, listUniqueTagsInDirectory, NULL,
|
ret = traverseAllIn(fp, NULL, listUniqueTagsInDirectory, NULL,
|
||||||
(void *)item);
|
(void *)item);
|
||||||
|
|
||||||
if(type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
|
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
|
||||||
printVisitedInTagTracker(fp, type);
|
printVisitedInTagTracker(fp, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,26 +421,31 @@ int listAllUniqueTags(FILE * fp, int type, int numConditionals,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sumSavedFilenameMemoryInDirectory(FILE * fp, Directory * dir, void * data) {
|
static int sumSavedFilenameMemoryInDirectory(FILE * fp, Directory * dir,
|
||||||
int * sum = data;
|
void *data)
|
||||||
|
{
|
||||||
|
int *sum = data;
|
||||||
|
|
||||||
if(!dir->path) return 0;
|
if (!dir->path)
|
||||||
|
return 0;
|
||||||
|
|
||||||
*sum += (strlen(getDirectoryPath(dir))+1-sizeof(Directory *))*
|
*sum += (strlen(getDirectoryPath(dir)) + 1 - sizeof(Directory *)) *
|
||||||
dir->songs->numberOfNodes;
|
dir->songs->numberOfNodes;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sumSavedFilenameMemoryInSong(FILE * fp, Song * song, void * data) {
|
static int sumSavedFilenameMemoryInSong(FILE * fp, Song * song, void *data)
|
||||||
int * sum = data;
|
{
|
||||||
|
int *sum = data;
|
||||||
|
|
||||||
*sum += strlen(song->url)+1;
|
*sum += strlen(song->url) + 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printSavedMemoryFromFilenames(void) {
|
void printSavedMemoryFromFilenames(void)
|
||||||
|
{
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|
||||||
traverseAllIn(stderr, NULL, sumSavedFilenameMemoryInSong,
|
traverseAllIn(stderr, NULL, sumSavedFilenameMemoryInSong,
|
||||||
|
@ -27,38 +27,36 @@
|
|||||||
typedef struct _LocateTagItem {
|
typedef struct _LocateTagItem {
|
||||||
mpd_sint8 tagType;
|
mpd_sint8 tagType;
|
||||||
/* what we are looking for */
|
/* what we are looking for */
|
||||||
char * needle;
|
char *needle;
|
||||||
} LocateTagItem;
|
} LocateTagItem;
|
||||||
|
|
||||||
int getLocateTagItemType(char * str);
|
int getLocateTagItemType(char *str);
|
||||||
|
|
||||||
/* returns NULL if not a known type */
|
/* returns NULL if not a known type */
|
||||||
LocateTagItem * newLocateTagItem(char * typeString, char * needle);
|
LocateTagItem *newLocateTagItem(char *typeString, char *needle);
|
||||||
|
|
||||||
/* return number of items or -1 on error */
|
/* return number of items or -1 on error */
|
||||||
int newLocateTagItemArrayFromArgArray(char * argArray[], int numArgs,
|
int newLocateTagItemArrayFromArgArray(char *argArray[], int numArgs,
|
||||||
LocateTagItem ** arrayRet);
|
LocateTagItem ** arrayRet);
|
||||||
|
|
||||||
|
|
||||||
void freeLocateTagItemArray(int count, LocateTagItem * array);
|
void freeLocateTagItemArray(int count, LocateTagItem * array);
|
||||||
|
|
||||||
void freeLocateTagItem(LocateTagItem * item);
|
void freeLocateTagItem(LocateTagItem * item);
|
||||||
|
|
||||||
int printAllIn(FILE * fp, char * name);
|
int printAllIn(FILE * fp, char *name);
|
||||||
|
|
||||||
int addAllIn(FILE * fp, char * name);
|
int addAllIn(FILE * fp, char *name);
|
||||||
|
|
||||||
int printInfoForAllIn(FILE * fp, char * name);
|
int printInfoForAllIn(FILE * fp, char *name);
|
||||||
|
|
||||||
int searchForSongsIn(FILE * fp, char * name, int numItems,
|
int searchForSongsIn(FILE * fp, char *name, int numItems,
|
||||||
LocateTagItem * items);
|
LocateTagItem * items);
|
||||||
|
|
||||||
int findSongsIn(FILE * fp, char * name, int numItems,
|
int findSongsIn(FILE * fp, char *name, int numItems, LocateTagItem * items);
|
||||||
LocateTagItem * items);
|
|
||||||
|
|
||||||
int countSongsIn(FILE * fp, char * name);
|
int countSongsIn(FILE * fp, char *name);
|
||||||
|
|
||||||
unsigned long sumSongTimesIn(FILE * fp, char * name);
|
unsigned long sumSongTimesIn(FILE * fp, char *name);
|
||||||
|
|
||||||
int listAllUniqueTags(FILE * fp, int type, int numConditiionals,
|
int listAllUniqueTags(FILE * fp, int type, int numConditiionals,
|
||||||
LocateTagItem * conditionals);
|
LocateTagItem * conditionals);
|
||||||
|
429
src/decode.c
429
src/decode.c
@ -39,40 +39,42 @@
|
|||||||
|
|
||||||
static int decode_pid = 0;
|
static int decode_pid = 0;
|
||||||
|
|
||||||
void decodeSigHandler(int sig, siginfo_t * si, void * v) {
|
void decodeSigHandler(int sig, siginfo_t * si, void *v)
|
||||||
if(sig==SIGCHLD) {
|
{
|
||||||
|
if (sig == SIGCHLD) {
|
||||||
int status;
|
int status;
|
||||||
if(decode_pid==wait3(&status,WNOHANG,NULL)) {
|
if (decode_pid == wait3(&status, WNOHANG, NULL)) {
|
||||||
if(WIFSIGNALED(status)) {
|
if (WIFSIGNALED(status)) {
|
||||||
if(WTERMSIG(status)!=SIGTERM) {
|
if (WTERMSIG(status) != SIGTERM) {
|
||||||
ERROR("decode process died from "
|
ERROR("decode process died from "
|
||||||
"signal: %i\n",
|
"signal: %i\n", WTERMSIG(status));
|
||||||
WTERMSIG(status));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decode_pid = 0;
|
decode_pid = 0;
|
||||||
getPlayerData()->playerControl.decode_pid = 0;
|
getPlayerData()->playerControl.decode_pid = 0;
|
||||||
}
|
}
|
||||||
}
|
} else if (sig == SIGTERM) {
|
||||||
else if(sig==SIGTERM) {
|
|
||||||
int pid = decode_pid;
|
int pid = decode_pid;
|
||||||
if(pid > 0) {
|
if (pid > 0) {
|
||||||
DEBUG("player (or child) got SIGTERM\n");
|
DEBUG("player (or child) got SIGTERM\n");
|
||||||
kill(pid,SIGTERM);
|
kill(pid, SIGTERM);
|
||||||
}
|
} else
|
||||||
else DEBUG("decoder (or child) got SIGTERM\n");
|
DEBUG("decoder (or child) got SIGTERM\n");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stopDecode(DecoderControl * dc) {
|
static void stopDecode(DecoderControl * dc)
|
||||||
if(decode_pid>0 && (dc->start || dc->state!=DECODE_STATE_STOP)) {
|
{
|
||||||
|
if (decode_pid > 0 && (dc->start || dc->state != DECODE_STATE_STOP)) {
|
||||||
dc->stop = 1;
|
dc->stop = 1;
|
||||||
while(decode_pid>0 && dc->stop) my_usleep(10000);
|
while (decode_pid > 0 && dc->stop)
|
||||||
|
my_usleep(10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quitDecode(PlayerControl * pc, DecoderControl * dc) {
|
static void quitDecode(PlayerControl * pc, DecoderControl * dc)
|
||||||
|
{
|
||||||
stopDecode(dc);
|
stopDecode(dc);
|
||||||
pc->metadataState = PLAYER_METADATA_STATE_READ;
|
pc->metadataState = PLAYER_METADATA_STATE_READ;
|
||||||
pc->state = PLAYER_STATE_STOP;
|
pc->state = PLAYER_STATE_STOP;
|
||||||
@ -80,22 +82,25 @@ static void quitDecode(PlayerControl * pc, DecoderControl * dc) {
|
|||||||
pc->play = 0;
|
pc->play = 0;
|
||||||
pc->stop = 0;
|
pc->stop = 0;
|
||||||
pc->pause = 0;
|
pc->pause = 0;
|
||||||
kill(getppid(),SIGUSR1);
|
kill(getppid(), SIGUSR1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
|
static int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af)
|
||||||
|
{
|
||||||
long chunks;
|
long chunks;
|
||||||
|
|
||||||
if(pc->crossFade<=0) return 0;
|
if (pc->crossFade <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
chunks = (af->sampleRate*af->bits*af->channels/8.0/CHUNK_SIZE);
|
chunks = (af->sampleRate * af->bits * af->channels / 8.0 / CHUNK_SIZE);
|
||||||
chunks = (chunks*pc->crossFade+0.5);
|
chunks = (chunks * pc->crossFade + 0.5);
|
||||||
|
|
||||||
if(chunks>(buffered_chunks-buffered_before_play)) {
|
if (chunks > (buffered_chunks - buffered_before_play)) {
|
||||||
chunks = buffered_chunks-buffered_before_play;
|
chunks = buffered_chunks - buffered_before_play;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(chunks<0) chunks = 0;
|
if (chunks < 0)
|
||||||
|
chunks = 0;
|
||||||
|
|
||||||
return (int)chunks;
|
return (int)chunks;
|
||||||
}
|
}
|
||||||
@ -136,24 +141,25 @@ static int calculateCrossFadeChunks(PlayerControl * pc, AudioFormat * af) {
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
static int waitOnDecode(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
|
static int waitOnDecode(PlayerControl * pc, DecoderControl * dc,
|
||||||
int * decodeWaitedOn)
|
OutputBuffer * cb, int *decodeWaitedOn)
|
||||||
{
|
{
|
||||||
MpdTag * tag = NULL;
|
MpdTag *tag = NULL;
|
||||||
strncpy(pc->currentUrl, pc->utf8url, MAXPATHLEN);
|
strncpy(pc->currentUrl, pc->utf8url, MAXPATHLEN);
|
||||||
pc->currentUrl[MAXPATHLEN] = '\0';
|
pc->currentUrl[MAXPATHLEN] = '\0';
|
||||||
|
|
||||||
while(decode_pid>0 && dc->start) my_usleep(10000);
|
while (decode_pid > 0 && dc->start)
|
||||||
|
my_usleep(10000);
|
||||||
|
|
||||||
if(dc->start || dc->error!=DECODE_ERROR_NOERROR) {
|
if (dc->start || dc->error != DECODE_ERROR_NOERROR) {
|
||||||
strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN);
|
strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN);
|
||||||
pc->erroredUrl[MAXPATHLEN] = '\0';
|
pc->erroredUrl[MAXPATHLEN] = '\0';
|
||||||
pc->error = PLAYER_ERROR_FILE;
|
pc->error = PLAYER_ERROR_FILE;
|
||||||
quitDecode(pc,dc);
|
quitDecode(pc, dc);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((tag = metadataChunkToMpdTagDup(&(pc->fileMetadataChunk)))) {
|
if ((tag = metadataChunkToMpdTagDup(&(pc->fileMetadataChunk)))) {
|
||||||
sendMetadataToAudioDevice(tag);
|
sendMetadataToAudioDevice(tag);
|
||||||
freeMpdTag(tag);
|
freeMpdTag(tag);
|
||||||
}
|
}
|
||||||
@ -168,35 +174,33 @@ static int waitOnDecode(PlayerControl * pc, DecoderControl * dc, OutputBuffer *
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decodeSeek(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
|
static int decodeSeek(PlayerControl * pc, DecoderControl * dc,
|
||||||
int * decodeWaitedOn, int * next)
|
OutputBuffer * cb, int *decodeWaitedOn, int *next)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if(decode_pid>0) {
|
if (decode_pid > 0) {
|
||||||
if(dc->state==DECODE_STATE_STOP || dc->error ||
|
if (dc->state == DECODE_STATE_STOP || dc->error ||
|
||||||
strcmp(dc->utf8url, pc->utf8url)!=0)
|
strcmp(dc->utf8url, pc->utf8url) != 0) {
|
||||||
{
|
|
||||||
stopDecode(dc);
|
stopDecode(dc);
|
||||||
*next = -1;
|
*next = -1;
|
||||||
cb->begin = 0;
|
cb->begin = 0;
|
||||||
cb->end = 0;
|
cb->end = 0;
|
||||||
dc->error = 0;
|
dc->error = 0;
|
||||||
dc->start = 1;
|
dc->start = 1;
|
||||||
waitOnDecode(pc,dc,cb,decodeWaitedOn);
|
waitOnDecode(pc, dc, cb, decodeWaitedOn);
|
||||||
}
|
}
|
||||||
if(decode_pid>0 && dc->state!=DECODE_STATE_STOP &&
|
if (decode_pid > 0 && dc->state != DECODE_STATE_STOP &&
|
||||||
dc->seekable)
|
dc->seekable) {
|
||||||
{
|
|
||||||
*next = -1;
|
*next = -1;
|
||||||
dc->seekWhere = pc->seekWhere > pc->totalTime-0.1 ?
|
dc->seekWhere = pc->seekWhere > pc->totalTime - 0.1 ?
|
||||||
pc->totalTime-0.1 :
|
pc->totalTime - 0.1 : pc->seekWhere;
|
||||||
pc->seekWhere;
|
|
||||||
dc->seekWhere = 0 > dc->seekWhere ? 0 : dc->seekWhere;
|
dc->seekWhere = 0 > dc->seekWhere ? 0 : dc->seekWhere;
|
||||||
dc->seekError = 0;
|
dc->seekError = 0;
|
||||||
dc->seek = 1;
|
dc->seek = 1;
|
||||||
while(decode_pid>0 && dc->seek) my_usleep(10000);
|
while (decode_pid > 0 && dc->seek)
|
||||||
if(!dc->seekError) {
|
my_usleep(10000);
|
||||||
|
if (!dc->seekError) {
|
||||||
pc->elapsedTime = dc->seekWhere;
|
pc->elapsedTime = dc->seekWhere;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
@ -256,23 +260,24 @@ static int decodeSeek(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb
|
|||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
|
||||||
|
DecoderControl * dc)
|
||||||
|
{
|
||||||
int ret;
|
int ret;
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
InputPlugin * plugin = NULL;
|
InputPlugin *plugin = NULL;
|
||||||
char * path;
|
char *path;
|
||||||
char * relativePath;
|
char *relativePath;
|
||||||
|
|
||||||
if(isRemoteUrl(pc->utf8url)) {
|
if (isRemoteUrl(pc->utf8url)) {
|
||||||
path = utf8StrToLatin1Dup(pc->utf8url);
|
path = utf8StrToLatin1Dup(pc->utf8url);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
relativePath = utf8ToFsCharset(pc->utf8url);
|
relativePath = utf8ToFsCharset(pc->utf8url);
|
||||||
path = strdup(rmp2amp(relativePath));
|
path = strdup(rmp2amp(relativePath));
|
||||||
free(relativePath);
|
free(relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!path) {
|
if (!path) {
|
||||||
dc->error = DECODE_ERROR_FILE;
|
dc->error = DECODE_ERROR_FILE;
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->start = 0;
|
dc->start = 0;
|
||||||
@ -284,7 +289,7 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl *
|
|||||||
strncpy(dc->utf8url, pc->utf8url, MAXPATHLEN);
|
strncpy(dc->utf8url, pc->utf8url, MAXPATHLEN);
|
||||||
dc->utf8url[MAXPATHLEN] = '\0';
|
dc->utf8url[MAXPATHLEN] = '\0';
|
||||||
|
|
||||||
if(openInputStream(&inStream, path) < 0) {
|
if (openInputStream(&inStream, path) < 0) {
|
||||||
dc->error = DECODE_ERROR_FILE;
|
dc->error = DECODE_ERROR_FILE;
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->start = 0;
|
dc->start = 0;
|
||||||
@ -296,14 +301,13 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl *
|
|||||||
dc->state = DECODE_STATE_START;
|
dc->state = DECODE_STATE_START;
|
||||||
dc->start = 0;
|
dc->start = 0;
|
||||||
|
|
||||||
while(!inputStreamAtEOF(&inStream) && bufferInputStream(&inStream) < 0
|
while (!inputStreamAtEOF(&inStream) && bufferInputStream(&inStream) < 0
|
||||||
&& !dc->stop)
|
&& !dc->stop) {
|
||||||
{
|
|
||||||
/* sleep so we don't consume 100% of the cpu */
|
/* sleep so we don't consume 100% of the cpu */
|
||||||
my_usleep(1000);
|
my_usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dc->stop) {
|
if (dc->stop) {
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
free(path);
|
free(path);
|
||||||
@ -315,88 +319,87 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl *
|
|||||||
tag->name = strdup(inStream.metaName);
|
tag->name = strdup(inStream.metaName);
|
||||||
copyMpdTagToOutputBuffer(cb, tag);
|
copyMpdTagToOutputBuffer(cb, tag);
|
||||||
freeMpdTag(tag);
|
freeMpdTag(tag);
|
||||||
}*/
|
} */
|
||||||
|
|
||||||
/* reset Metadata in OutputBuffer */
|
/* reset Metadata in OutputBuffer */
|
||||||
|
|
||||||
ret = DECODE_ERROR_UNKTYPE;
|
ret = DECODE_ERROR_UNKTYPE;
|
||||||
if(isRemoteUrl(dc->utf8url)) {
|
if (isRemoteUrl(dc->utf8url)) {
|
||||||
unsigned int next = 0;
|
unsigned int next = 0;
|
||||||
cb->acceptMetadata = 1;
|
cb->acceptMetadata = 1;
|
||||||
|
|
||||||
/* first we try mime types: */
|
/* first we try mime types: */
|
||||||
while(ret && (plugin = getInputPluginFromMimeType(
|
while (ret
|
||||||
inStream.mime, next++))) {
|
&& (plugin =
|
||||||
|
getInputPluginFromMimeType(inStream.mime, next++))) {
|
||||||
if (!plugin->streamDecodeFunc)
|
if (!plugin->streamDecodeFunc)
|
||||||
continue;
|
continue;
|
||||||
if (!(plugin->streamTypes & INPUT_PLUGIN_STREAM_URL))
|
if (!(plugin->streamTypes & INPUT_PLUGIN_STREAM_URL))
|
||||||
continue;
|
continue;
|
||||||
if(plugin->tryDecodeFunc && !plugin->tryDecodeFunc(
|
if (plugin->tryDecodeFunc
|
||||||
&inStream))
|
&& !plugin->tryDecodeFunc(&inStream))
|
||||||
continue;
|
continue;
|
||||||
ret = plugin->streamDecodeFunc(cb, dc, &inStream);
|
ret = plugin->streamDecodeFunc(cb, dc, &inStream);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if that fails, try suffix matching the URL: */
|
/* if that fails, try suffix matching the URL: */
|
||||||
if(plugin == NULL) {
|
if (plugin == NULL) {
|
||||||
char * s = getSuffix(dc->utf8url);
|
char *s = getSuffix(dc->utf8url);
|
||||||
next = 0;
|
next = 0;
|
||||||
while(ret && (plugin = getInputPluginFromSuffix(
|
while (ret
|
||||||
s, next++))) {
|
&& (plugin =
|
||||||
|
getInputPluginFromSuffix(s, next++))) {
|
||||||
if (!plugin->streamDecodeFunc)
|
if (!plugin->streamDecodeFunc)
|
||||||
continue;
|
continue;
|
||||||
if(!(plugin->streamTypes &
|
if (!(plugin->streamTypes &
|
||||||
INPUT_PLUGIN_STREAM_URL))
|
INPUT_PLUGIN_STREAM_URL))
|
||||||
continue;
|
continue;
|
||||||
if(plugin->tryDecodeFunc &&
|
if (plugin->tryDecodeFunc &&
|
||||||
!plugin->tryDecodeFunc(
|
!plugin->tryDecodeFunc(&inStream))
|
||||||
&inStream))
|
|
||||||
continue;
|
continue;
|
||||||
ret = plugin->streamDecodeFunc(
|
ret =
|
||||||
cb, dc, &inStream);
|
plugin->streamDecodeFunc(cb, dc, &inStream);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* fallback to mp3: */
|
/* fallback to mp3: */
|
||||||
/* this is needed for bastard streams that don't have a suffix
|
/* this is needed for bastard streams that don't have a suffix
|
||||||
or set the mimeType */
|
or set the mimeType */
|
||||||
if(plugin == NULL) {
|
if (plugin == NULL) {
|
||||||
/* we already know our mp3Plugin supports streams, no
|
/* we already know our mp3Plugin supports streams, no
|
||||||
* need to check for stream{Types,DecodeFunc} */
|
* need to check for stream{Types,DecodeFunc} */
|
||||||
if ((plugin = getInputPluginFromName("mp3")))
|
if ((plugin = getInputPluginFromName("mp3")))
|
||||||
ret = plugin->streamDecodeFunc(cb, dc,
|
ret = plugin->streamDecodeFunc(cb, dc,
|
||||||
&inStream);
|
&inStream);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
unsigned int next = 0;
|
unsigned int next = 0;
|
||||||
char * s = getSuffix(dc->utf8url);
|
char *s = getSuffix(dc->utf8url);
|
||||||
cb->acceptMetadata = 0;
|
cb->acceptMetadata = 0;
|
||||||
while (ret && (plugin = getInputPluginFromSuffix(s, next++))) {
|
while (ret && (plugin = getInputPluginFromSuffix(s, next++))) {
|
||||||
if(!plugin->streamTypes & INPUT_PLUGIN_STREAM_FILE)
|
if (!plugin->streamTypes & INPUT_PLUGIN_STREAM_FILE)
|
||||||
continue;
|
continue;
|
||||||
if(plugin->tryDecodeFunc && !plugin->tryDecodeFunc(
|
if (plugin->tryDecodeFunc
|
||||||
&inStream))
|
&& !plugin->tryDecodeFunc(&inStream))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(plugin->streamDecodeFunc) {
|
if (plugin->streamDecodeFunc) {
|
||||||
ret = plugin->streamDecodeFunc(
|
ret =
|
||||||
cb, dc, &inStream);
|
plugin->streamDecodeFunc(cb, dc, &inStream);
|
||||||
break;
|
break;
|
||||||
}
|
} else if (plugin->fileDecodeFunc) {
|
||||||
else if(plugin->fileDecodeFunc) {
|
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
ret = plugin->fileDecodeFunc(
|
ret = plugin->fileDecodeFunc(cb, dc, path);
|
||||||
cb, dc, path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ret<0 || ret == DECODE_ERROR_UNKTYPE) {
|
if (ret < 0 || ret == DECODE_ERROR_UNKTYPE) {
|
||||||
strncpy(pc->erroredUrl, dc->utf8url, MAXPATHLEN);
|
strncpy(pc->erroredUrl, dc->utf8url, MAXPATHLEN);
|
||||||
pc->erroredUrl[MAXPATHLEN] = '\0';
|
pc->erroredUrl[MAXPATHLEN] = '\0';
|
||||||
if(ret != DECODE_ERROR_UNKTYPE) dc->error = DECODE_ERROR_FILE;
|
if (ret != DECODE_ERROR_UNKTYPE)
|
||||||
|
dc->error = DECODE_ERROR_FILE;
|
||||||
else {
|
else {
|
||||||
dc->error = DECODE_ERROR_UNKTYPE;
|
dc->error = DECODE_ERROR_UNKTYPE;
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
@ -408,32 +411,33 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb, DecoderControl *
|
|||||||
free(path);
|
free(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decoderInit(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
static int decoderInit(PlayerControl * pc, OutputBuffer * cb,
|
||||||
|
DecoderControl * dc)
|
||||||
|
{
|
||||||
blockSignals();
|
blockSignals();
|
||||||
getPlayerData()->playerControl.decode_pid = 0;
|
getPlayerData()->playerControl.decode_pid = 0;
|
||||||
decode_pid = fork();
|
decode_pid = fork();
|
||||||
|
|
||||||
if(decode_pid==0) {
|
if (decode_pid == 0) {
|
||||||
/* CHILD */
|
/* CHILD */
|
||||||
unblockSignals();
|
unblockSignals();
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
if(dc->cycleLogFiles) {
|
if (dc->cycleLogFiles) {
|
||||||
myfprintfCloseAndOpenLogFile();
|
myfprintfCloseAndOpenLogFile();
|
||||||
dc->cycleLogFiles = 0;
|
dc->cycleLogFiles = 0;
|
||||||
}
|
} else if (dc->start || dc->seek)
|
||||||
else if(dc->start || dc->seek) decodeStart(pc, cb, dc);
|
decodeStart(pc, cb, dc);
|
||||||
else if(dc->stop) {
|
else if (dc->stop) {
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
}
|
} else
|
||||||
else my_usleep(10000);
|
my_usleep(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
/* END OF CHILD */
|
/* END OF CHILD */
|
||||||
}
|
} else if (decode_pid < 0) {
|
||||||
else if(decode_pid<0) {
|
|
||||||
unblockSignals();
|
unblockSignals();
|
||||||
strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN);
|
strncpy(pc->erroredUrl, pc->utf8url, MAXPATHLEN);
|
||||||
pc->erroredUrl[MAXPATHLEN] = '\0';
|
pc->erroredUrl[MAXPATHLEN] = '\0';
|
||||||
@ -447,17 +451,17 @@ static int decoderInit(PlayerControl * pc, OutputBuffer * cb, DecoderControl * d
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handleMetadata(OutputBuffer * cb, PlayerControl * pc, int * previous,
|
static void handleMetadata(OutputBuffer * cb, PlayerControl * pc, int *previous,
|
||||||
int * currentChunkSent, MetadataChunk * currentChunk)
|
int *currentChunkSent, MetadataChunk * currentChunk)
|
||||||
{
|
{
|
||||||
if(cb->begin!=cb->end) {
|
if (cb->begin != cb->end) {
|
||||||
int meta = cb->metaChunk[cb->begin];
|
int meta = cb->metaChunk[cb->begin];
|
||||||
if( meta != *previous ) {
|
if (meta != *previous) {
|
||||||
DEBUG("player: metadata change\n");
|
DEBUG("player: metadata change\n");
|
||||||
if( meta >= 0 && cb->metaChunkSet[meta]) {
|
if (meta >= 0 && cb->metaChunkSet[meta]) {
|
||||||
DEBUG("player: new metadata from decoder!\n");
|
DEBUG("player: new metadata from decoder!\n");
|
||||||
memcpy(currentChunk,
|
memcpy(currentChunk,
|
||||||
cb->metadataChunks+meta,
|
cb->metadataChunks + meta,
|
||||||
sizeof(MetadataChunk));
|
sizeof(MetadataChunk));
|
||||||
*currentChunkSent = 0;
|
*currentChunkSent = 0;
|
||||||
cb->metaChunkSet[meta] = 0;
|
cb->metaChunkSet[meta] = 0;
|
||||||
@ -465,14 +469,13 @@ static void handleMetadata(OutputBuffer * cb, PlayerControl * pc, int * previous
|
|||||||
}
|
}
|
||||||
*previous = meta;
|
*previous = meta;
|
||||||
}
|
}
|
||||||
if(!(*currentChunkSent) && pc->metadataState ==
|
if (!(*currentChunkSent) && pc->metadataState ==
|
||||||
PLAYER_METADATA_STATE_WRITE)
|
PLAYER_METADATA_STATE_WRITE) {
|
||||||
{
|
MpdTag *tag = NULL;
|
||||||
MpdTag * tag = NULL;
|
|
||||||
|
|
||||||
*currentChunkSent = 1;
|
*currentChunkSent = 1;
|
||||||
|
|
||||||
if((tag = metadataChunkToMpdTagDup(currentChunk))) {
|
if ((tag = metadataChunkToMpdTagDup(currentChunk))) {
|
||||||
sendMetadataToAudioDevice(tag);
|
sendMetadataToAudioDevice(tag);
|
||||||
freeMpdTag(tag);
|
freeMpdTag(tag);
|
||||||
}
|
}
|
||||||
@ -485,20 +488,21 @@ static void handleMetadata(OutputBuffer * cb, PlayerControl * pc, int * previous
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void advanceOutputBufferTo(OutputBuffer * cb, PlayerControl * pc,
|
static void advanceOutputBufferTo(OutputBuffer * cb, PlayerControl * pc,
|
||||||
int * previous, int * currentChunkSent, MetadataChunk * currentChunk,
|
int *previous, int *currentChunkSent,
|
||||||
int to)
|
MetadataChunk * currentChunk, int to)
|
||||||
{
|
{
|
||||||
while(cb->begin!=to) {
|
while (cb->begin != to) {
|
||||||
handleMetadata(cb, pc, previous, currentChunkSent,
|
handleMetadata(cb, pc, previous, currentChunkSent,
|
||||||
currentChunk);
|
currentChunk);
|
||||||
cb->begin++;
|
cb->begin++;
|
||||||
if(cb->begin>=buffered_chunks) {
|
if (cb->begin >= buffered_chunks) {
|
||||||
cb->begin = 0;
|
cb->begin = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
|
void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb)
|
||||||
|
{
|
||||||
int pause = 0;
|
int pause = 0;
|
||||||
int quit = 0;
|
int quit = 0;
|
||||||
int bbp = buffered_before_play;
|
int bbp = buffered_before_play;
|
||||||
@ -516,133 +520,125 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
|
|||||||
int end;
|
int end;
|
||||||
int next = -1;
|
int next = -1;
|
||||||
|
|
||||||
memset(silence,0,CHUNK_SIZE);
|
memset(silence, 0, CHUNK_SIZE);
|
||||||
|
|
||||||
if(waitOnDecode(pc,dc,cb,&decodeWaitedOn)<0) return;
|
if (waitOnDecode(pc, dc, cb, &decodeWaitedOn) < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
pc->elapsedTime = 0;
|
pc->elapsedTime = 0;
|
||||||
pc->state = PLAYER_STATE_PLAY;
|
pc->state = PLAYER_STATE_PLAY;
|
||||||
pc->play = 0;
|
pc->play = 0;
|
||||||
kill(getppid(),SIGUSR1);
|
kill(getppid(), SIGUSR1);
|
||||||
|
|
||||||
while(decode_pid>0 && cb->end-cb->begin<bbp &&
|
while (decode_pid > 0 && cb->end - cb->begin < bbp &&
|
||||||
cb->end!=buffered_chunks-1 &&
|
cb->end != buffered_chunks - 1 &&
|
||||||
dc->state!=DECODE_STATE_STOP)
|
dc->state != DECODE_STATE_STOP) {
|
||||||
{
|
|
||||||
processDecodeInput();
|
processDecodeInput();
|
||||||
my_usleep(1000);
|
my_usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(!quit) {
|
while (!quit) {
|
||||||
processDecodeInput();
|
processDecodeInput();
|
||||||
handleDecodeStart();
|
handleDecodeStart();
|
||||||
handleMetadata(cb, pc, &previousMetadataChunk,
|
handleMetadata(cb, pc, &previousMetadataChunk,
|
||||||
¤tChunkSent, ¤tMetadataChunk);
|
¤tChunkSent, ¤tMetadataChunk);
|
||||||
if(dc->state==DECODE_STATE_STOP &&
|
if (dc->state == DECODE_STATE_STOP &&
|
||||||
pc->queueState==PLAYER_QUEUE_FULL &&
|
pc->queueState == PLAYER_QUEUE_FULL &&
|
||||||
pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
|
pc->queueLockState == PLAYER_QUEUE_UNLOCKED) {
|
||||||
{
|
|
||||||
next = cb->end;
|
next = cb->end;
|
||||||
dc->start = 1;
|
dc->start = 1;
|
||||||
pc->queueState = PLAYER_QUEUE_DECODE;
|
pc->queueState = PLAYER_QUEUE_DECODE;
|
||||||
kill(getppid(),SIGUSR1);
|
kill(getppid(), SIGUSR1);
|
||||||
}
|
}
|
||||||
if(next>=0 && doCrossFade==0 && !dc->start &&
|
if (next >= 0 && doCrossFade == 0 && !dc->start &&
|
||||||
dc->state!=DECODE_STATE_START)
|
dc->state != DECODE_STATE_START) {
|
||||||
{
|
|
||||||
nextChunk = -1;
|
nextChunk = -1;
|
||||||
if(isCurrentAudioFormat(&(cb->audioFormat))) {
|
if (isCurrentAudioFormat(&(cb->audioFormat))) {
|
||||||
doCrossFade = 1;
|
doCrossFade = 1;
|
||||||
crossFadeChunks =
|
crossFadeChunks =
|
||||||
calculateCrossFadeChunks(pc,
|
calculateCrossFadeChunks(pc,
|
||||||
&(cb->audioFormat));
|
&(cb->
|
||||||
if(!crossFadeChunks ||
|
audioFormat));
|
||||||
pc->crossFade>=dc->totalTime)
|
if (!crossFadeChunks
|
||||||
{
|
|| pc->crossFade >= dc->totalTime) {
|
||||||
doCrossFade = -1;
|
doCrossFade = -1;
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else doCrossFade = -1;
|
doCrossFade = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* copy these to local variables to prevent any potential
|
/* copy these to local variables to prevent any potential
|
||||||
race conditions and weirdness */
|
race conditions and weirdness */
|
||||||
end = cb->end;
|
end = cb->end;
|
||||||
|
|
||||||
if(pause) my_usleep(10000);
|
if (pause)
|
||||||
else if(cb->begin!=end && cb->begin!=next) {
|
my_usleep(10000);
|
||||||
if(doCrossFade==1 && next>=0 &&
|
else if (cb->begin != end && cb->begin != next) {
|
||||||
((next>cb->begin &&
|
if (doCrossFade == 1 && next >= 0 &&
|
||||||
(fadePosition=next-cb->begin)
|
((next > cb->begin &&
|
||||||
<=crossFadeChunks) ||
|
(fadePosition = next - cb->begin)
|
||||||
(cb->begin>next &&
|
<= crossFadeChunks) ||
|
||||||
(fadePosition=next-cb->begin+
|
(cb->begin > next &&
|
||||||
buffered_chunks)<=crossFadeChunks)))
|
(fadePosition = next - cb->begin +
|
||||||
{
|
buffered_chunks) <= crossFadeChunks))) {
|
||||||
if(nextChunk<0) {
|
if (nextChunk < 0) {
|
||||||
crossFadeChunks = fadePosition;
|
crossFadeChunks = fadePosition;
|
||||||
}
|
}
|
||||||
test = end;
|
test = end;
|
||||||
if(end < cb->begin) test+=buffered_chunks;
|
if (end < cb->begin)
|
||||||
nextChunk = cb->begin+crossFadeChunks;
|
test += buffered_chunks;
|
||||||
if(nextChunk<test) {
|
nextChunk = cb->begin + crossFadeChunks;
|
||||||
if(nextChunk>=buffered_chunks)
|
if (nextChunk < test) {
|
||||||
{
|
if (nextChunk >= buffered_chunks) {
|
||||||
nextChunk -= buffered_chunks;
|
nextChunk -= buffered_chunks;
|
||||||
}
|
}
|
||||||
pcm_mix(cb->chunks+cb->begin*CHUNK_SIZE,
|
pcm_mix(cb->chunks +
|
||||||
cb->chunks+nextChunk*
|
cb->begin * CHUNK_SIZE,
|
||||||
CHUNK_SIZE,
|
cb->chunks +
|
||||||
cb->chunkSize[
|
nextChunk * CHUNK_SIZE,
|
||||||
cb->begin],
|
cb->chunkSize[cb->begin],
|
||||||
cb->chunkSize[
|
cb->chunkSize[nextChunk],
|
||||||
nextChunk],
|
|
||||||
&(cb->audioFormat),
|
&(cb->audioFormat),
|
||||||
((float)fadePosition)/
|
((float)fadePosition) /
|
||||||
crossFadeChunks);
|
crossFadeChunks);
|
||||||
if(cb->chunkSize[nextChunk]>
|
if (cb->chunkSize[nextChunk] >
|
||||||
cb->chunkSize[cb->begin]
|
cb->chunkSize[cb->begin]
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
cb->chunkSize[cb->begin]
|
cb->chunkSize[cb->begin]
|
||||||
= cb->chunkSize
|
= cb->chunkSize[nextChunk];
|
||||||
[nextChunk];
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (dc->state == DECODE_STATE_STOP) {
|
||||||
if(dc->state==DECODE_STATE_STOP)
|
|
||||||
{
|
|
||||||
doCrossFade = -1;
|
doCrossFade = -1;
|
||||||
}
|
} else
|
||||||
else continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pc->elapsedTime = cb->times[cb->begin];
|
pc->elapsedTime = cb->times[cb->begin];
|
||||||
pc->bitRate = cb->bitRate[cb->begin];
|
pc->bitRate = cb->bitRate[cb->begin];
|
||||||
pcm_volumeChange(cb->chunks+cb->begin*
|
pcm_volumeChange(cb->chunks + cb->begin *
|
||||||
CHUNK_SIZE,
|
CHUNK_SIZE,
|
||||||
cb->chunkSize[cb->begin],
|
cb->chunkSize[cb->begin],
|
||||||
&(cb->audioFormat),
|
&(cb->audioFormat),
|
||||||
pc->softwareVolume);
|
pc->softwareVolume);
|
||||||
if(playAudio(cb->chunks+cb->begin*CHUNK_SIZE,
|
if (playAudio(cb->chunks + cb->begin * CHUNK_SIZE,
|
||||||
cb->chunkSize[cb->begin])<0)
|
cb->chunkSize[cb->begin]) < 0) {
|
||||||
{
|
|
||||||
quit = 1;
|
quit = 1;
|
||||||
}
|
}
|
||||||
pc->totalPlayTime+= sizeToTime*cb->chunkSize[cb->begin];
|
pc->totalPlayTime +=
|
||||||
if( cb->begin+1 >= buffered_chunks ) {
|
sizeToTime * cb->chunkSize[cb->begin];
|
||||||
|
if (cb->begin + 1 >= buffered_chunks) {
|
||||||
cb->begin = 0;
|
cb->begin = 0;
|
||||||
}
|
} else
|
||||||
else cb->begin++;
|
cb->begin++;
|
||||||
}
|
} else if (next == cb->begin) {
|
||||||
else if(next==cb->begin) {
|
if (doCrossFade == 1 && nextChunk >= 0) {
|
||||||
if(doCrossFade==1 && nextChunk>=0) {
|
nextChunk = cb->begin + crossFadeChunks;
|
||||||
nextChunk = cb->begin+crossFadeChunks;
|
|
||||||
test = cb->end;
|
test = cb->end;
|
||||||
if(end < cb->begin) test+=buffered_chunks;
|
if (end < cb->begin)
|
||||||
if(nextChunk<test) {
|
test += buffered_chunks;
|
||||||
if(nextChunk>=buffered_chunks)
|
if (nextChunk < test) {
|
||||||
{
|
if (nextChunk >= buffered_chunks) {
|
||||||
nextChunk -= buffered_chunks;
|
nextChunk -= buffered_chunks;
|
||||||
}
|
}
|
||||||
advanceOutputBufferTo(cb, pc,
|
advanceOutputBufferTo(cb, pc,
|
||||||
@ -652,44 +648,41 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
|
|||||||
nextChunk);
|
nextChunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(pc->queueState==PLAYER_QUEUE_DECODE ||
|
while (pc->queueState == PLAYER_QUEUE_DECODE ||
|
||||||
pc->queueLockState==PLAYER_QUEUE_LOCKED)
|
pc->queueLockState == PLAYER_QUEUE_LOCKED) {
|
||||||
{
|
|
||||||
processDecodeInput();
|
processDecodeInput();
|
||||||
if(quit) {
|
if (quit) {
|
||||||
quitDecode(pc,dc);
|
quitDecode(pc, dc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
my_usleep(10000);
|
my_usleep(10000);
|
||||||
}
|
}
|
||||||
if(pc->queueState!=PLAYER_QUEUE_PLAY) {
|
if (pc->queueState != PLAYER_QUEUE_PLAY) {
|
||||||
quit = 1;
|
quit = 1;
|
||||||
break;
|
break;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
next = -1;
|
next = -1;
|
||||||
if(waitOnDecode(pc,dc,cb,&decodeWaitedOn)<0) {
|
if (waitOnDecode(pc, dc, cb, &decodeWaitedOn) <
|
||||||
|
0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nextChunk = -1;
|
nextChunk = -1;
|
||||||
doCrossFade = 0;
|
doCrossFade = 0;
|
||||||
crossFadeChunks = 0;
|
crossFadeChunks = 0;
|
||||||
pc->queueState = PLAYER_QUEUE_EMPTY;
|
pc->queueState = PLAYER_QUEUE_EMPTY;
|
||||||
kill(getppid(),SIGUSR1);
|
kill(getppid(), SIGUSR1);
|
||||||
}
|
}
|
||||||
}
|
} else if (decode_pid <= 0 ||
|
||||||
else if(decode_pid<=0 ||
|
(dc->state == DECODE_STATE_STOP && !dc->start)) {
|
||||||
(dc->state==DECODE_STATE_STOP && !dc->start))
|
|
||||||
{
|
|
||||||
quit = 1;
|
quit = 1;
|
||||||
break;
|
break;
|
||||||
}
|
} else {
|
||||||
else {
|
if (playAudio(silence, CHUNK_SIZE) < 0)
|
||||||
if(playAudio(silence, CHUNK_SIZE) < 0) quit = 1;
|
quit = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quitDecode(pc,dc);
|
quitDecode(pc, dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decode w/ buffering
|
/* decode w/ buffering
|
||||||
@ -697,10 +690,11 @@ void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb) {
|
|||||||
* child process does decoding
|
* child process does decoding
|
||||||
* parent process does playing audio
|
* parent process does playing audio
|
||||||
*/
|
*/
|
||||||
void decode() {
|
void decode()
|
||||||
OutputBuffer * cb;
|
{
|
||||||
PlayerControl * pc;
|
OutputBuffer *cb;
|
||||||
DecoderControl * dc;
|
PlayerControl *pc;
|
||||||
|
DecoderControl *dc;
|
||||||
|
|
||||||
cb = &(getPlayerData()->buffer);
|
cb = &(getPlayerData()->buffer);
|
||||||
|
|
||||||
@ -714,8 +708,9 @@ void decode() {
|
|||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
dc->start = 1;
|
dc->start = 1;
|
||||||
|
|
||||||
if(decode_pid<=0) {
|
if (decode_pid <= 0) {
|
||||||
if(decoderInit(pc,cb,dc)<0) return;
|
if (decoderInit(pc, cb, dc) < 0)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
decodeParent(pc, dc, cb);
|
decodeParent(pc, dc, cb);
|
||||||
|
@ -58,11 +58,11 @@ typedef struct _DecoderControl {
|
|||||||
volatile mpd_sint8 cycleLogFiles;
|
volatile mpd_sint8 cycleLogFiles;
|
||||||
volatile double seekWhere;
|
volatile double seekWhere;
|
||||||
AudioFormat audioFormat;
|
AudioFormat audioFormat;
|
||||||
char utf8url[MAXPATHLEN+1];
|
char utf8url[MAXPATHLEN + 1];
|
||||||
volatile float totalTime;
|
volatile float totalTime;
|
||||||
} DecoderControl;
|
} DecoderControl;
|
||||||
|
|
||||||
void decodeSigHandler(int sig, siginfo_t * siginfo, void * v);
|
void decodeSigHandler(int sig, siginfo_t * siginfo, void *v);
|
||||||
|
|
||||||
void decode();
|
void decode();
|
||||||
|
|
||||||
|
993
src/directory.c
993
src/directory.c
File diff suppressed because it is too large
Load Diff
@ -32,11 +32,11 @@ typedef struct _DirectoryStat {
|
|||||||
} DirectoryStat;
|
} DirectoryStat;
|
||||||
|
|
||||||
typedef struct _Directory {
|
typedef struct _Directory {
|
||||||
char * path;
|
char *path;
|
||||||
DirectoryList * subDirectories;
|
DirectoryList *subDirectories;
|
||||||
SongList * songs;
|
SongList *songs;
|
||||||
struct _Directory * parent;
|
struct _Directory *parent;
|
||||||
DirectoryStat * stat;
|
DirectoryStat *stat;
|
||||||
} Directory;
|
} Directory;
|
||||||
|
|
||||||
void readDirectoryDBIfUpdateIsFinished();
|
void readDirectoryDBIfUpdateIsFinished();
|
||||||
@ -51,7 +51,7 @@ void initMp3Directory();
|
|||||||
|
|
||||||
void closeMp3Directory();
|
void closeMp3Directory();
|
||||||
|
|
||||||
int printDirectoryInfo(FILE * fp, char * dirname);
|
int printDirectoryInfo(FILE * fp, char *dirname);
|
||||||
|
|
||||||
int checkDirectoryDB();
|
int checkDirectoryDB();
|
||||||
|
|
||||||
@ -61,14 +61,13 @@ int readDirectoryDB();
|
|||||||
|
|
||||||
void updateMp3Directory();
|
void updateMp3Directory();
|
||||||
|
|
||||||
Song * getSongFromDB(char * file);
|
Song *getSongFromDB(char *file);
|
||||||
|
|
||||||
time_t getDbModTime();
|
time_t getDbModTime();
|
||||||
|
|
||||||
int traverseAllIn(FILE * fp, char * name,
|
int traverseAllIn(FILE * fp, char *name,
|
||||||
int (*forEachSong)(FILE *, Song *, void *),
|
int (*forEachSong) (FILE *, Song *, void *),
|
||||||
int (*forEachDir)(FILE *, Directory *, void *),
|
int (*forEachDir) (FILE *, Directory *, void *), void *data);
|
||||||
void * data);
|
|
||||||
|
|
||||||
#define getDirectoryPath(dir) ((dir && dir->path) ? dir->path : "")
|
#define getDirectoryPath(dir) ((dir && dir->path) ? dir->path : "")
|
||||||
|
|
||||||
|
@ -24,47 +24,59 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static List * inputPlugin_list = NULL;
|
static List *inputPlugin_list = NULL;
|
||||||
|
|
||||||
void loadInputPlugin(InputPlugin * inputPlugin) {
|
void loadInputPlugin(InputPlugin * inputPlugin)
|
||||||
if(!inputPlugin) return;
|
{
|
||||||
if(!inputPlugin->name) return;
|
if (!inputPlugin)
|
||||||
|
return;
|
||||||
|
if (!inputPlugin->name)
|
||||||
|
return;
|
||||||
|
|
||||||
if(inputPlugin->initFunc && inputPlugin->initFunc() < 0) return;
|
if (inputPlugin->initFunc && inputPlugin->initFunc() < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
insertInList(inputPlugin_list, inputPlugin->name, (void *)inputPlugin);
|
insertInList(inputPlugin_list, inputPlugin->name, (void *)inputPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unloadInputPlugin(InputPlugin * inputPlugin) {
|
void unloadInputPlugin(InputPlugin * inputPlugin)
|
||||||
if(inputPlugin->finishFunc) inputPlugin->finishFunc();
|
{
|
||||||
|
if (inputPlugin->finishFunc)
|
||||||
|
inputPlugin->finishFunc();
|
||||||
deleteFromList(inputPlugin_list, inputPlugin->name);
|
deleteFromList(inputPlugin_list, inputPlugin->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stringFoundInStringArray(char ** array, char * suffix) {
|
static int stringFoundInStringArray(char **array, char *suffix)
|
||||||
while(array && *array) {
|
{
|
||||||
if(strcasecmp(*array, suffix) == 0) return 1;
|
while (array && *array) {
|
||||||
|
if (strcasecmp(*array, suffix) == 0)
|
||||||
|
return 1;
|
||||||
array++;
|
array++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputPlugin * getInputPluginFromSuffix(char * suffix, unsigned int next) {
|
InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next)
|
||||||
static ListNode * pos = NULL;
|
{
|
||||||
ListNode * node;
|
static ListNode *pos = NULL;
|
||||||
InputPlugin * plugin;
|
ListNode *node;
|
||||||
|
InputPlugin *plugin;
|
||||||
|
|
||||||
if(suffix == NULL) return NULL;
|
if (suffix == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (next) {
|
if (next) {
|
||||||
if (pos) node = pos;
|
if (pos)
|
||||||
else return NULL;
|
node = pos;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
} else
|
} else
|
||||||
node = inputPlugin_list->firstNode;
|
node = inputPlugin_list->firstNode;
|
||||||
|
|
||||||
while(node != NULL) {
|
while (node != NULL) {
|
||||||
plugin = node->data;
|
plugin = node->data;
|
||||||
if(stringFoundInStringArray(plugin->suffixes, suffix)) {
|
if (stringFoundInStringArray(plugin->suffixes, suffix)) {
|
||||||
pos = node->nextNode;
|
pos = node->nextNode;
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
@ -74,18 +86,20 @@ InputPlugin * getInputPluginFromSuffix(char * suffix, unsigned int next) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputPlugin * getInputPluginFromMimeType(char * mimeType, unsigned int next) {
|
InputPlugin *getInputPluginFromMimeType(char *mimeType, unsigned int next)
|
||||||
static ListNode * pos = NULL;
|
{
|
||||||
ListNode * node;
|
static ListNode *pos = NULL;
|
||||||
InputPlugin * plugin;
|
ListNode *node;
|
||||||
|
InputPlugin *plugin;
|
||||||
|
|
||||||
if(mimeType == NULL) return NULL;
|
if (mimeType == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
node = (next && pos) ? pos : inputPlugin_list->firstNode;
|
node = (next && pos) ? pos : inputPlugin_list->firstNode;
|
||||||
|
|
||||||
while(node != NULL) {
|
while (node != NULL) {
|
||||||
plugin = node->data;
|
plugin = node->data;
|
||||||
if(stringFoundInStringArray(plugin->mimeTypes, mimeType)) {
|
if (stringFoundInStringArray(plugin->mimeTypes, mimeType)) {
|
||||||
pos = node->nextNode;
|
pos = node->nextNode;
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
@ -95,23 +109,25 @@ InputPlugin * getInputPluginFromMimeType(char * mimeType, unsigned int next) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputPlugin * getInputPluginFromName(char * name) {
|
InputPlugin *getInputPluginFromName(char *name)
|
||||||
void * plugin = NULL;
|
{
|
||||||
|
void *plugin = NULL;
|
||||||
|
|
||||||
findInList(inputPlugin_list, name, &plugin);
|
findInList(inputPlugin_list, name, &plugin);
|
||||||
|
|
||||||
return (InputPlugin *)plugin;
|
return (InputPlugin *) plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printAllInputPluginSuffixes(FILE * fp) {
|
void printAllInputPluginSuffixes(FILE * fp)
|
||||||
ListNode * node = inputPlugin_list->firstNode;
|
{
|
||||||
InputPlugin * plugin;
|
ListNode *node = inputPlugin_list->firstNode;
|
||||||
char ** suffixes;
|
InputPlugin *plugin;
|
||||||
|
char **suffixes;
|
||||||
|
|
||||||
while(node) {
|
while (node) {
|
||||||
plugin = (InputPlugin *)node->data;
|
plugin = (InputPlugin *) node->data;
|
||||||
suffixes = plugin->suffixes;
|
suffixes = plugin->suffixes;
|
||||||
while(suffixes && *suffixes) {
|
while (suffixes && *suffixes) {
|
||||||
myfprintf(fp, "%s ", *suffixes);
|
myfprintf(fp, "%s ", *suffixes);
|
||||||
suffixes++;
|
suffixes++;
|
||||||
}
|
}
|
||||||
@ -130,7 +146,8 @@ extern InputPlugin mpcPlugin;
|
|||||||
extern InputPlugin aacPlugin;
|
extern InputPlugin aacPlugin;
|
||||||
extern InputPlugin modPlugin;
|
extern InputPlugin modPlugin;
|
||||||
|
|
||||||
void initInputPlugins(void) {
|
void initInputPlugins(void)
|
||||||
|
{
|
||||||
inputPlugin_list = makeList(NULL, 1);
|
inputPlugin_list = makeList(NULL, 1);
|
||||||
|
|
||||||
/* load plugins here */
|
/* load plugins here */
|
||||||
@ -144,6 +161,7 @@ void initInputPlugins(void) {
|
|||||||
loadInputPlugin(&modPlugin);
|
loadInputPlugin(&modPlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishInputPlugins(void) {
|
void finishInputPlugins(void)
|
||||||
|
{
|
||||||
freeList(inputPlugin_list);
|
freeList(inputPlugin_list);
|
||||||
}
|
}
|
||||||
|
@ -31,20 +31,20 @@
|
|||||||
|
|
||||||
/* optional, set this to NULL if the InputPlugin doesn't have/need one
|
/* optional, set this to NULL if the InputPlugin doesn't have/need one
|
||||||
* this must return < 0 if there is an error and >= 0 otherwise */
|
* this must return < 0 if there is an error and >= 0 otherwise */
|
||||||
typedef int (* InputPlugin_initFunc) ();
|
typedef int (*InputPlugin_initFunc) ();
|
||||||
|
|
||||||
/* optional, set this to NULL if the InputPlugin doesn't have/need one */
|
/* optional, set this to NULL if the InputPlugin doesn't have/need one */
|
||||||
typedef void (* InputPlugin_finishFunc) ();
|
typedef void (*InputPlugin_finishFunc) ();
|
||||||
|
|
||||||
/* boolean return value, returns 1 if the InputStream is decodable by
|
/* boolean return value, returns 1 if the InputStream is decodable by
|
||||||
* the InputPlugin, 0 if not */
|
* the InputPlugin, 0 if not */
|
||||||
typedef unsigned int (* InputPlugin_tryDecodeFunc) (InputStream *);
|
typedef unsigned int (*InputPlugin_tryDecodeFunc) (InputStream *);
|
||||||
|
|
||||||
/* this will be used to decode InputStreams, and is recommended for files
|
/* this will be used to decode InputStreams, and is recommended for files
|
||||||
* and networked (HTTP) connections.
|
* and networked (HTTP) connections.
|
||||||
*
|
*
|
||||||
* returns -1 on error, 0 on success */
|
* returns -1 on error, 0 on success */
|
||||||
typedef int (* InputPlugin_streamDecodeFunc) (OutputBuffer *, DecoderControl *,
|
typedef int (*InputPlugin_streamDecodeFunc) (OutputBuffer *, DecoderControl *,
|
||||||
InputStream *);
|
InputStream *);
|
||||||
|
|
||||||
/* use this if and only if your InputPlugin can only be passed a filename or
|
/* use this if and only if your InputPlugin can only be passed a filename or
|
||||||
@ -52,15 +52,15 @@ typedef int (* InputPlugin_streamDecodeFunc) (OutputBuffer *, DecoderControl *,
|
|||||||
* and FLAC libraries allow)
|
* and FLAC libraries allow)
|
||||||
*
|
*
|
||||||
* returns -1 on error, 0 on success */
|
* returns -1 on error, 0 on success */
|
||||||
typedef int (* InputPlugin_fileDecodeFunc) (OutputBuffer *, DecoderControl *,
|
typedef int (*InputPlugin_fileDecodeFunc) (OutputBuffer *, DecoderControl *,
|
||||||
char * path);
|
char *path);
|
||||||
|
|
||||||
/* file should be the full path! Returns NULL if a tag cannot be found
|
/* file should be the full path! Returns NULL if a tag cannot be found
|
||||||
* or read */
|
* or read */
|
||||||
typedef MpdTag * (* InputPlugin_tagDupFunc) (char * file);
|
typedef MpdTag *(*InputPlugin_tagDupFunc) (char *file);
|
||||||
|
|
||||||
typedef struct _InputPlugin {
|
typedef struct _InputPlugin {
|
||||||
char * name;
|
char *name;
|
||||||
InputPlugin_initFunc initFunc;
|
InputPlugin_initFunc initFunc;
|
||||||
InputPlugin_finishFunc finishFunc;
|
InputPlugin_finishFunc finishFunc;
|
||||||
InputPlugin_tryDecodeFunc tryDecodeFunc;
|
InputPlugin_tryDecodeFunc tryDecodeFunc;
|
||||||
@ -72,8 +72,8 @@ typedef struct _InputPlugin {
|
|||||||
unsigned char streamTypes;
|
unsigned char streamTypes;
|
||||||
|
|
||||||
/* last element in these arrays must always be a NULL: */
|
/* last element in these arrays must always be a NULL: */
|
||||||
char ** suffixes;
|
char **suffixes;
|
||||||
char ** mimeTypes;
|
char **mimeTypes;
|
||||||
} InputPlugin;
|
} InputPlugin;
|
||||||
|
|
||||||
/* individual functions to load/unload plugins */
|
/* individual functions to load/unload plugins */
|
||||||
@ -82,11 +82,11 @@ void unloadInputPlugin(InputPlugin * inputPlugin);
|
|||||||
|
|
||||||
/* interface for using plugins */
|
/* interface for using plugins */
|
||||||
|
|
||||||
InputPlugin * getInputPluginFromSuffix(char * suffix, unsigned int next);
|
InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next);
|
||||||
|
|
||||||
InputPlugin * getInputPluginFromMimeType(char * mimeType, unsigned int next);
|
InputPlugin *getInputPluginFromMimeType(char *mimeType, unsigned int next);
|
||||||
|
|
||||||
InputPlugin * getInputPluginFromName(char * name);
|
InputPlugin *getInputPluginFromName(char *name);
|
||||||
|
|
||||||
void printAllInputPluginSuffixes(FILE * fp);
|
void printAllInputPluginSuffixes(FILE * fp);
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
#include <FLAC/format.h>
|
#include <FLAC/format.h>
|
||||||
#include <FLAC/metadata.h>
|
#include <FLAC/metadata.h>
|
||||||
|
|
||||||
void init_FlacData (FlacData * data, OutputBuffer * cb,
|
void init_FlacData(FlacData * data, OutputBuffer * cb,
|
||||||
DecoderControl * dc, InputStream * inStream)
|
DecoderControl * dc, InputStream * inStream)
|
||||||
{
|
{
|
||||||
data->chunk_length = 0;
|
data->chunk_length = 0;
|
||||||
@ -53,18 +53,18 @@ void init_FlacData (FlacData * data, OutputBuffer * cb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block,
|
static int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block,
|
||||||
char * cmnt, float * fl)
|
char *cmnt, float *fl)
|
||||||
{
|
{
|
||||||
int offset = FLAC__metadata_object_vorbiscomment_find_entry_from(
|
int offset =
|
||||||
block,0,cmnt);
|
FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, cmnt);
|
||||||
|
|
||||||
if(offset >= 0) {
|
if (offset >= 0) {
|
||||||
size_t pos = strlen(cmnt)+1; /* 1 is for '=' */
|
size_t pos = strlen(cmnt) + 1; /* 1 is for '=' */
|
||||||
int len = block->data.vorbis_comment.comments[offset].length
|
int len = block->data.vorbis_comment.comments[offset].length
|
||||||
-pos;
|
- pos;
|
||||||
if(len > 0) {
|
if (len > 0) {
|
||||||
unsigned char tmp;
|
unsigned char tmp;
|
||||||
unsigned char * dup = &(block->data.vorbis_comment.
|
unsigned char *dup = &(block->data.vorbis_comment.
|
||||||
comments[offset].entry[pos]);
|
comments[offset].entry[pos]);
|
||||||
tmp = dup[len];
|
tmp = dup[len];
|
||||||
dup[len] = '\0';
|
dup[len] = '\0';
|
||||||
@ -79,8 +79,9 @@ static int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* replaygain stuff by AliasMrJones */
|
/* replaygain stuff by AliasMrJones */
|
||||||
static void flacParseReplayGain(const FLAC__StreamMetadata *block,
|
static void flacParseReplayGain(const FLAC__StreamMetadata * block,
|
||||||
FlacData * data) {
|
FlacData * data)
|
||||||
|
{
|
||||||
unsigned int found = 0;
|
unsigned int found = 0;
|
||||||
|
|
||||||
if (data->replayGainInfo)
|
if (data->replayGainInfo)
|
||||||
@ -88,13 +89,13 @@ static void flacParseReplayGain(const FLAC__StreamMetadata *block,
|
|||||||
|
|
||||||
data->replayGainInfo = newReplayGainInfo();
|
data->replayGainInfo = newReplayGainInfo();
|
||||||
|
|
||||||
found &= flacFindVorbisCommentFloat(block,"replaygain_album_gain",
|
found &= flacFindVorbisCommentFloat(block, "replaygain_album_gain",
|
||||||
&data->replayGainInfo->albumGain);
|
&data->replayGainInfo->albumGain);
|
||||||
found &= flacFindVorbisCommentFloat(block,"replaygain_album_peak",
|
found &= flacFindVorbisCommentFloat(block, "replaygain_album_peak",
|
||||||
&data->replayGainInfo->albumPeak);
|
&data->replayGainInfo->albumPeak);
|
||||||
found &= flacFindVorbisCommentFloat(block,"replaygain_track_gain",
|
found &= flacFindVorbisCommentFloat(block, "replaygain_track_gain",
|
||||||
&data->replayGainInfo->trackGain);
|
&data->replayGainInfo->trackGain);
|
||||||
found &= flacFindVorbisCommentFloat(block,"replaygain_track_peak",
|
found &= flacFindVorbisCommentFloat(block, "replaygain_track_peak",
|
||||||
&data->replayGainInfo->trackPeak);
|
&data->replayGainInfo->trackPeak);
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
@ -105,33 +106,38 @@ static void flacParseReplayGain(const FLAC__StreamMetadata *block,
|
|||||||
|
|
||||||
/* tracknumber is used in VCs, MPD uses "track" ..., all the other
|
/* tracknumber is used in VCs, MPD uses "track" ..., all the other
|
||||||
* tag names match */
|
* tag names match */
|
||||||
static const char * VORBIS_COMMENT_TRACK_KEY = "tracknumber";
|
static const char *VORBIS_COMMENT_TRACK_KEY = "tracknumber";
|
||||||
static const char * VORBIS_COMMENT_DISC_KEY = "discnumber";
|
static const char *VORBIS_COMMENT_DISC_KEY = "discnumber";
|
||||||
|
|
||||||
static unsigned int commentMatchesAddToTag(
|
static unsigned int commentMatchesAddToTag(const
|
||||||
const FLAC__StreamMetadata_VorbisComment_Entry * entry,
|
FLAC__StreamMetadata_VorbisComment_Entry
|
||||||
unsigned int itemType,
|
* entry, unsigned int itemType,
|
||||||
MpdTag ** tag)
|
MpdTag ** tag)
|
||||||
{
|
{
|
||||||
const char * str;
|
const char *str;
|
||||||
size_t slen;
|
size_t slen;
|
||||||
int vlen;
|
int vlen;
|
||||||
|
|
||||||
switch (itemType) {
|
switch (itemType) {
|
||||||
case TAG_ITEM_TRACK: str = VORBIS_COMMENT_TRACK_KEY; break;
|
case TAG_ITEM_TRACK:
|
||||||
case TAG_ITEM_DISC: str = VORBIS_COMMENT_DISC_KEY; break;
|
str = VORBIS_COMMENT_TRACK_KEY;
|
||||||
default: str = mpdTagItemKeys[itemType];
|
break;
|
||||||
|
case TAG_ITEM_DISC:
|
||||||
|
str = VORBIS_COMMENT_DISC_KEY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
str = mpdTagItemKeys[itemType];
|
||||||
}
|
}
|
||||||
slen = strlen(str);
|
slen = strlen(str);
|
||||||
vlen = entry->length - slen - 1;
|
vlen = entry->length - slen - 1;
|
||||||
|
|
||||||
if ((vlen > 0) && (0 == strncasecmp(str,(char *)entry->entry, slen))
|
if ((vlen > 0) && (0 == strncasecmp(str, (char *)entry->entry, slen))
|
||||||
&& (*(entry->entry + slen) == '=')) {
|
&& (*(entry->entry + slen) == '=')) {
|
||||||
if (!*tag)
|
if (!*tag)
|
||||||
*tag = newMpdTag();
|
*tag = newMpdTag();
|
||||||
|
|
||||||
addItemToMpdTagWithLen(*tag, itemType,
|
addItemToMpdTagWithLen(*tag, itemType,
|
||||||
(char *)(entry->entry+slen + 1), vlen);
|
(char *)(entry->entry + slen + 1), vlen);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -139,7 +145,7 @@ static unsigned int commentMatchesAddToTag(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
MpdTag * copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
|
MpdTag *copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
|
||||||
MpdTag * tag)
|
MpdTag * tag)
|
||||||
{
|
{
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
@ -148,7 +154,7 @@ MpdTag * copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
|
|||||||
comments = block->data.vorbis_comment.comments;
|
comments = block->data.vorbis_comment.comments;
|
||||||
|
|
||||||
for (i = block->data.vorbis_comment.num_comments; i != 0; --i) {
|
for (i = block->data.vorbis_comment.num_comments; i != 0; --i) {
|
||||||
for (j = TAG_NUM_OF_ITEM_TYPES; j--; ) {
|
for (j = TAG_NUM_OF_ITEM_TYPES; j--;) {
|
||||||
if (commentMatchesAddToTag(comments, j, &tag))
|
if (commentMatchesAddToTag(comments, j, &tag))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -158,12 +164,13 @@ MpdTag * copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
|
|||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void flac_metadata_common_cb(const FLAC__StreamMetadata *block, FlacData *data)
|
void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
|
||||||
|
FlacData * data)
|
||||||
{
|
{
|
||||||
DecoderControl *dc = data->dc;
|
DecoderControl *dc = data->dc;
|
||||||
const FLAC__StreamMetadata_StreamInfo *si = &(block->data.stream_info);
|
const FLAC__StreamMetadata_StreamInfo *si = &(block->data.stream_info);
|
||||||
|
|
||||||
switch(block->type) {
|
switch (block->type) {
|
||||||
case FLAC__METADATA_TYPE_STREAMINFO:
|
case FLAC__METADATA_TYPE_STREAMINFO:
|
||||||
dc->audioFormat.bits = si->bits_per_sample;
|
dc->audioFormat.bits = si->bits_per_sample;
|
||||||
dc->audioFormat.sampleRate = si->sample_rate;
|
dc->audioFormat.sampleRate = si->sample_rate;
|
||||||
@ -173,19 +180,20 @@ void flac_metadata_common_cb(const FLAC__StreamMetadata *block, FlacData *data)
|
|||||||
&(data->cb->audioFormat));
|
&(data->cb->audioFormat));
|
||||||
break;
|
break;
|
||||||
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
|
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
|
||||||
flacParseReplayGain(block,data);
|
flacParseReplayGain(block, data);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flac_error_common_cb( const char * plugin,
|
void flac_error_common_cb(const char *plugin,
|
||||||
const FLAC__StreamDecoderErrorStatus status,
|
const FLAC__StreamDecoderErrorStatus status,
|
||||||
FlacData *data)
|
FlacData * data)
|
||||||
{
|
{
|
||||||
if(data->dc->stop) return;
|
if (data->dc->stop)
|
||||||
|
return;
|
||||||
|
|
||||||
switch(status) {
|
switch (status) {
|
||||||
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
|
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
|
||||||
ERROR("%s lost sync\n", plugin);
|
ERROR("%s lost sync\n", plugin);
|
||||||
break;
|
break;
|
||||||
@ -196,7 +204,7 @@ void flac_error_common_cb( const char * plugin,
|
|||||||
ERROR("%s crc mismatch\n", plugin);
|
ERROR("%s crc mismatch\n", plugin);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERROR("unknown %s error\n",plugin);
|
ERROR("unknown %s error\n", plugin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,38 +41,38 @@ typedef struct {
|
|||||||
float time;
|
float time;
|
||||||
int bitRate;
|
int bitRate;
|
||||||
FLAC__uint64 position;
|
FLAC__uint64 position;
|
||||||
OutputBuffer * cb;
|
OutputBuffer *cb;
|
||||||
DecoderControl * dc;
|
DecoderControl *dc;
|
||||||
InputStream * inStream;
|
InputStream *inStream;
|
||||||
ReplayGainInfo * replayGainInfo;
|
ReplayGainInfo *replayGainInfo;
|
||||||
MpdTag * tag;
|
MpdTag *tag;
|
||||||
} FlacData;
|
} FlacData;
|
||||||
|
|
||||||
/* initializes a given FlacData struct */
|
/* initializes a given FlacData struct */
|
||||||
void init_FlacData (FlacData * data, OutputBuffer * cb,
|
void init_FlacData(FlacData * data, OutputBuffer * cb,
|
||||||
DecoderControl * dc, InputStream * inStream);
|
DecoderControl * dc, InputStream * inStream);
|
||||||
void flac_metadata_common_cb( const FLAC__StreamMetadata *block,
|
void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
|
||||||
FlacData *data);
|
FlacData * data);
|
||||||
void flac_error_common_cb( const char * plugin,
|
void flac_error_common_cb(const char *plugin,
|
||||||
FLAC__StreamDecoderErrorStatus status,
|
FLAC__StreamDecoderErrorStatus status,
|
||||||
FlacData *data);
|
FlacData * data);
|
||||||
|
|
||||||
MpdTag * copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
|
MpdTag *copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
|
||||||
MpdTag * tag);
|
MpdTag * tag);
|
||||||
|
|
||||||
/* keep this inlined, this is just macro but prettier :) */
|
/* keep this inlined, this is just macro but prettier :) */
|
||||||
static inline int flacSendChunk(FlacData * data)
|
static inline int flacSendChunk(FlacData * data)
|
||||||
{
|
{
|
||||||
if (sendDataToOutputBuffer(data->cb, NULL, data->dc, 1, data->chunk,
|
if (sendDataToOutputBuffer(data->cb, NULL, data->dc, 1, data->chunk,
|
||||||
data->chunk_length, data->time, data->bitRate,
|
data->chunk_length, data->time,
|
||||||
data->replayGainInfo) == OUTPUT_BUFFER_DC_STOP)
|
data->bitRate,
|
||||||
|
data->replayGainInfo) ==
|
||||||
|
OUTPUT_BUFFER_DC_STOP)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* HAVE_FLAC || HAVE_OGGFLAC */
|
#endif /* HAVE_FLAC || HAVE_OGGFLAC */
|
||||||
|
|
||||||
#endif /* _FLAC_COMMON_H */
|
#endif /* _FLAC_COMMON_H */
|
||||||
|
|
||||||
|
@ -51,15 +51,23 @@ ogg_stream_type ogg_stream_type_detect(InputStream * inStream)
|
|||||||
|
|
||||||
seekInputStream(inStream, 0, SEEK_SET);
|
seekInputStream(inStream, 0, SEEK_SET);
|
||||||
|
|
||||||
if (r >= 32 && memcmp(buf, "OggS", 4) == 0 && (
|
if (r >= 32 && memcmp(buf, "OggS", 4) == 0 && ((memcmp
|
||||||
(memcmp(buf+29, "FLAC", 4) == 0
|
(buf + 29, "FLAC",
|
||||||
&& memcmp(buf+37, "fLaC", 4) == 0)
|
4) == 0
|
||||||
|| (memcmp(buf+28, "FLAC", 4) == 0)
|
&& memcmp(buf + 37,
|
||||||
|| (memcmp(buf+28, "fLaC", 4) == 0))) {
|
"fLaC",
|
||||||
|
4) == 0)
|
||||||
|
||
|
||||||
|
(memcmp
|
||||||
|
(buf + 28, "FLAC",
|
||||||
|
4) == 0)
|
||||||
|
||
|
||||||
|
(memcmp
|
||||||
|
(buf + 28, "fLaC",
|
||||||
|
4) == 0))) {
|
||||||
return FLAC;
|
return FLAC;
|
||||||
}
|
}
|
||||||
return VORBIS;
|
return VORBIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* defined(HAVE_OGGFLAC || defined(HAVE_OGGVORBIS) */
|
#endif /* defined(HAVE_OGGFLAC || defined(HAVE_OGGVORBIS) */
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
/* all code here is either based on or copied from FAAD2's frontend code */
|
/* all code here is either based on or copied from FAAD2's frontend code */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
InputStream * inStream;
|
InputStream *inStream;
|
||||||
long bytesIntoBuffer;
|
long bytesIntoBuffer;
|
||||||
long bytesConsumed;
|
long bytesConsumed;
|
||||||
long fileOffset;
|
long fileOffset;
|
||||||
@ -44,163 +44,193 @@ typedef struct {
|
|||||||
int atEof;
|
int atEof;
|
||||||
} AacBuffer;
|
} AacBuffer;
|
||||||
|
|
||||||
static void fillAacBuffer(AacBuffer *b) {
|
static void fillAacBuffer(AacBuffer * b)
|
||||||
if(b->bytesConsumed > 0) {
|
{
|
||||||
|
if (b->bytesConsumed > 0) {
|
||||||
int bread;
|
int bread;
|
||||||
|
|
||||||
if(b->bytesIntoBuffer) {
|
if (b->bytesIntoBuffer) {
|
||||||
memmove((void *)b->buffer,(void*)(b->buffer+
|
memmove((void *)b->buffer, (void *)(b->buffer +
|
||||||
b->bytesConsumed),b->bytesIntoBuffer);
|
b->bytesConsumed),
|
||||||
|
b->bytesIntoBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!b->atEof) {
|
if (!b->atEof) {
|
||||||
bread = readFromInputStream(b->inStream,
|
bread = readFromInputStream(b->inStream,
|
||||||
(void *)(b->buffer+b->bytesIntoBuffer),
|
(void *)(b->buffer +
|
||||||
1,b->bytesConsumed);
|
b->
|
||||||
if(bread!=b->bytesConsumed) b->atEof = 1;
|
bytesIntoBuffer),
|
||||||
b->bytesIntoBuffer+=bread;
|
1, b->bytesConsumed);
|
||||||
|
if (bread != b->bytesConsumed)
|
||||||
|
b->atEof = 1;
|
||||||
|
b->bytesIntoBuffer += bread;
|
||||||
}
|
}
|
||||||
|
|
||||||
b->bytesConsumed = 0;
|
b->bytesConsumed = 0;
|
||||||
|
|
||||||
if(b->bytesIntoBuffer > 3) {
|
if (b->bytesIntoBuffer > 3) {
|
||||||
if(memcmp(b->buffer,"TAG",3)==0) b->bytesIntoBuffer = 0;
|
if (memcmp(b->buffer, "TAG", 3) == 0)
|
||||||
|
b->bytesIntoBuffer = 0;
|
||||||
}
|
}
|
||||||
if(b->bytesIntoBuffer > 11) {
|
if (b->bytesIntoBuffer > 11) {
|
||||||
if(memcmp(b->buffer,"LYRICSBEGIN",11)==0) {
|
if (memcmp(b->buffer, "LYRICSBEGIN", 11) == 0) {
|
||||||
b->bytesIntoBuffer = 0;
|
b->bytesIntoBuffer = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(b->bytesIntoBuffer > 8) {
|
if (b->bytesIntoBuffer > 8) {
|
||||||
if(memcmp(b->buffer,"APETAGEX",8)==0) {
|
if (memcmp(b->buffer, "APETAGEX", 8) == 0) {
|
||||||
b->bytesIntoBuffer = 0;
|
b->bytesIntoBuffer = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void advanceAacBuffer(AacBuffer * b, int bytes) {
|
static void advanceAacBuffer(AacBuffer * b, int bytes)
|
||||||
b->fileOffset+=bytes;
|
{
|
||||||
|
b->fileOffset += bytes;
|
||||||
b->bytesConsumed = bytes;
|
b->bytesConsumed = bytes;
|
||||||
b->bytesIntoBuffer-=bytes;
|
b->bytesIntoBuffer -= bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adtsSampleRates[] = {96000,88200,64000,48000,44100,32000,24000,22050,
|
static int adtsSampleRates[] =
|
||||||
16000,12000,11025,8000,7350,0,0,0};
|
{ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
|
||||||
|
16000, 12000, 11025, 8000, 7350, 0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
static int adtsParse(AacBuffer * b, float * length) {
|
static int adtsParse(AacBuffer * b, float *length)
|
||||||
|
{
|
||||||
int frames, frameLength;
|
int frames, frameLength;
|
||||||
int tFrameLength = 0;
|
int tFrameLength = 0;
|
||||||
int sampleRate = 0;
|
int sampleRate = 0;
|
||||||
float framesPerSec, bytesPerFrame;
|
float framesPerSec, bytesPerFrame;
|
||||||
|
|
||||||
/* Read all frames to ensure correct time and bitrate */
|
/* Read all frames to ensure correct time and bitrate */
|
||||||
for(frames = 0; ;frames++) {
|
for (frames = 0;; frames++) {
|
||||||
fillAacBuffer(b);
|
fillAacBuffer(b);
|
||||||
|
|
||||||
if(b->bytesIntoBuffer > 7) {
|
if (b->bytesIntoBuffer > 7) {
|
||||||
/* check syncword */
|
/* check syncword */
|
||||||
if (!((b->buffer[0] == 0xFF) &&
|
if (!((b->buffer[0] == 0xFF) &&
|
||||||
((b->buffer[1] & 0xF6) == 0xF0)))
|
((b->buffer[1] & 0xF6) == 0xF0))) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(frames==0) {
|
if (frames == 0) {
|
||||||
sampleRate = adtsSampleRates[
|
sampleRate = adtsSampleRates[(b->
|
||||||
(b->buffer[2]&0x3c)>>2];
|
buffer[2] & 0x3c)
|
||||||
|
>> 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
frameLength = ((((unsigned int)b->buffer[3] & 0x3))
|
frameLength = ((((unsigned int)b->buffer[3] & 0x3))
|
||||||
<< 11) | (((unsigned int)b->buffer[4])
|
<< 11) | (((unsigned int)b->buffer[4])
|
||||||
<< 3) | (b->buffer[5] >> 5);
|
<< 3) | (b->buffer[5] >> 5);
|
||||||
|
|
||||||
tFrameLength+=frameLength;
|
tFrameLength += frameLength;
|
||||||
|
|
||||||
if(frameLength > b->bytesIntoBuffer) break;
|
if (frameLength > b->bytesIntoBuffer)
|
||||||
|
break;
|
||||||
|
|
||||||
advanceAacBuffer(b,frameLength);
|
advanceAacBuffer(b, frameLength);
|
||||||
}
|
} else
|
||||||
else break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
framesPerSec = (float)sampleRate/1024.0;
|
framesPerSec = (float)sampleRate / 1024.0;
|
||||||
if(frames!=0) {
|
if (frames != 0) {
|
||||||
bytesPerFrame = (float)tFrameLength/(float)(frames*1000);
|
bytesPerFrame = (float)tFrameLength / (float)(frames * 1000);
|
||||||
}
|
} else
|
||||||
else bytesPerFrame = 0;
|
bytesPerFrame = 0;
|
||||||
if(framesPerSec!=0) *length = (float)frames/framesPerSec;
|
if (framesPerSec != 0)
|
||||||
|
*length = (float)frames / framesPerSec;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initAacBuffer(InputStream * inStream, AacBuffer * b, float * length,
|
static void initAacBuffer(InputStream * inStream, AacBuffer * b, float *length,
|
||||||
size_t * retFileread, size_t * retTagsize)
|
size_t * retFileread, size_t * retTagsize)
|
||||||
{
|
{
|
||||||
size_t fileread;
|
size_t fileread;
|
||||||
size_t bread;
|
size_t bread;
|
||||||
size_t tagsize;
|
size_t tagsize;
|
||||||
|
|
||||||
if(length) *length = -1;
|
if (length)
|
||||||
|
*length = -1;
|
||||||
|
|
||||||
memset(b,0,sizeof(AacBuffer));
|
memset(b, 0, sizeof(AacBuffer));
|
||||||
|
|
||||||
b->inStream = inStream;
|
b->inStream = inStream;
|
||||||
|
|
||||||
fileread = inStream->size;
|
fileread = inStream->size;
|
||||||
|
|
||||||
b->buffer = malloc(FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
|
b->buffer = malloc(FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
|
||||||
memset(b->buffer,0,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
|
memset(b->buffer, 0, FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
|
||||||
|
|
||||||
bread = readFromInputStream(inStream,b->buffer,1,
|
bread = readFromInputStream(inStream, b->buffer, 1,
|
||||||
FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
|
FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
|
||||||
b->bytesIntoBuffer = bread;
|
b->bytesIntoBuffer = bread;
|
||||||
b->bytesConsumed = 0;
|
b->bytesConsumed = 0;
|
||||||
b->fileOffset = 0;
|
b->fileOffset = 0;
|
||||||
|
|
||||||
if(bread!=FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS) b->atEof = 1;
|
if (bread != FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS)
|
||||||
|
b->atEof = 1;
|
||||||
|
|
||||||
tagsize = 0;
|
tagsize = 0;
|
||||||
if(!memcmp(b->buffer,"ID3",3)) {
|
if (!memcmp(b->buffer, "ID3", 3)) {
|
||||||
tagsize = (b->buffer[6] << 21) | (b->buffer[7] << 14) |
|
tagsize = (b->buffer[6] << 21) | (b->buffer[7] << 14) |
|
||||||
(b->buffer[8] << 7) | (b->buffer[9] << 0);
|
(b->buffer[8] << 7) | (b->buffer[9] << 0);
|
||||||
|
|
||||||
tagsize+=10;
|
tagsize += 10;
|
||||||
advanceAacBuffer(b,tagsize);
|
advanceAacBuffer(b, tagsize);
|
||||||
fillAacBuffer(b);
|
fillAacBuffer(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(retFileread) *retFileread = fileread;
|
if (retFileread)
|
||||||
if(retTagsize) *retTagsize = tagsize;
|
*retFileread = fileread;
|
||||||
|
if (retTagsize)
|
||||||
|
*retTagsize = tagsize;
|
||||||
|
|
||||||
if(length==NULL) return;
|
if (length == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if((b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0)) {
|
if ((b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0)) {
|
||||||
adtsParse(b, length);
|
adtsParse(b, length);
|
||||||
seekInputStream(b->inStream, tagsize, SEEK_SET);
|
seekInputStream(b->inStream, tagsize, SEEK_SET);
|
||||||
|
|
||||||
bread = readFromInputStream(b->inStream, b->buffer, 1,
|
bread = readFromInputStream(b->inStream, b->buffer, 1,
|
||||||
FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
|
FAAD_MIN_STREAMSIZE *
|
||||||
if(bread != FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS) b->atEof = 1;
|
AAC_MAX_CHANNELS);
|
||||||
else b->atEof = 0;
|
if (bread != FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS)
|
||||||
|
b->atEof = 1;
|
||||||
|
else
|
||||||
|
b->atEof = 0;
|
||||||
b->bytesIntoBuffer = bread;
|
b->bytesIntoBuffer = bread;
|
||||||
b->bytesConsumed = 0;
|
b->bytesConsumed = 0;
|
||||||
b->fileOffset = tagsize;
|
b->fileOffset = tagsize;
|
||||||
}
|
} else if (memcmp(b->buffer, "ADIF", 4) == 0) {
|
||||||
else if(memcmp(b->buffer,"ADIF",4) == 0) {
|
|
||||||
int bitRate;
|
int bitRate;
|
||||||
int skipSize = (b->buffer[4] & 0x80) ? 9 : 0;
|
int skipSize = (b->buffer[4] & 0x80) ? 9 : 0;
|
||||||
bitRate = ((unsigned int)(b->buffer[4 + skipSize] & 0x0F)<<19) |
|
bitRate =
|
||||||
((unsigned int)b->buffer[5 + skipSize]<<11) |
|
((unsigned int)(b->
|
||||||
((unsigned int)b->buffer[6 + skipSize]<<3) |
|
buffer[4 +
|
||||||
((unsigned int)b->buffer[7 + skipSize] & 0xE0);
|
skipSize] & 0x0F) << 19) | ((unsigned
|
||||||
|
int)b->
|
||||||
|
buffer[5
|
||||||
|
+
|
||||||
|
skipSize]
|
||||||
|
<< 11) |
|
||||||
|
((unsigned int)b->
|
||||||
|
buffer[6 + skipSize] << 3) | ((unsigned int)b->buffer[7 +
|
||||||
|
skipSize]
|
||||||
|
& 0xE0);
|
||||||
|
|
||||||
*length = fileread;
|
*length = fileread;
|
||||||
if(*length!=0 && bitRate!=0) *length = *length*8.0/bitRate;
|
if (*length != 0 && bitRate != 0)
|
||||||
|
*length = *length * 8.0 / bitRate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static float getAacFloatTotalTime(char * file) {
|
static float getAacFloatTotalTime(char *file)
|
||||||
|
{
|
||||||
AacBuffer b;
|
AacBuffer b;
|
||||||
float length;
|
float length;
|
||||||
size_t fileread, tagsize;
|
size_t fileread, tagsize;
|
||||||
@ -211,46 +241,51 @@ static float getAacFloatTotalTime(char * file) {
|
|||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
size_t bread;
|
size_t bread;
|
||||||
|
|
||||||
if(openInputStream(&inStream,file) < 0) return -1;
|
if (openInputStream(&inStream, file) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
initAacBuffer(&inStream,&b,&length,&fileread,&tagsize);
|
initAacBuffer(&inStream, &b, &length, &fileread, &tagsize);
|
||||||
|
|
||||||
if(length < 0) {
|
if (length < 0) {
|
||||||
decoder = faacDecOpen();
|
decoder = faacDecOpen();
|
||||||
|
|
||||||
config = faacDecGetCurrentConfiguration(decoder);
|
config = faacDecGetCurrentConfiguration(decoder);
|
||||||
config->outputFormat = FAAD_FMT_16BIT;
|
config->outputFormat = FAAD_FMT_16BIT;
|
||||||
faacDecSetConfiguration(decoder,config);
|
faacDecSetConfiguration(decoder, config);
|
||||||
|
|
||||||
fillAacBuffer(&b);
|
fillAacBuffer(&b);
|
||||||
#ifdef HAVE_FAAD_BUFLEN_FUNCS
|
#ifdef HAVE_FAAD_BUFLEN_FUNCS
|
||||||
bread = faacDecInit(decoder,b.buffer,b.bytesIntoBuffer,
|
bread = faacDecInit(decoder, b.buffer, b.bytesIntoBuffer,
|
||||||
&sampleRate,&channels);
|
&sampleRate, &channels);
|
||||||
#else
|
#else
|
||||||
bread = faacDecInit(decoder,b.buffer,&sampleRate,&channels);
|
bread = faacDecInit(decoder, b.buffer, &sampleRate, &channels);
|
||||||
#endif
|
#endif
|
||||||
if(bread >= 0 && sampleRate > 0 && channels > 0) length = 0;
|
if (bread >= 0 && sampleRate > 0 && channels > 0)
|
||||||
|
length = 0;
|
||||||
|
|
||||||
faacDecClose(decoder);
|
faacDecClose(decoder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(b.buffer) free(b.buffer);
|
if (b.buffer)
|
||||||
|
free(b.buffer);
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getAacTotalTime(char * file) {
|
static int getAacTotalTime(char *file)
|
||||||
|
{
|
||||||
int time = -1;
|
int time = -1;
|
||||||
float length;
|
float length;
|
||||||
|
|
||||||
if((length = getAacFloatTotalTime(file))>=0) time = length+0.5;
|
if ((length = getAacFloatTotalTime(file)) >= 0)
|
||||||
|
time = length + 0.5;
|
||||||
|
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
|
||||||
static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
{
|
||||||
float time;
|
float time;
|
||||||
float totalTime;
|
float totalTime;
|
||||||
faacDecHandle decoder;
|
faacDecHandle decoder;
|
||||||
@ -261,20 +296,22 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
unsigned char channels;
|
unsigned char channels;
|
||||||
int eof = 0;
|
int eof = 0;
|
||||||
unsigned int sampleCount;
|
unsigned int sampleCount;
|
||||||
char * sampleBuffer;
|
char *sampleBuffer;
|
||||||
size_t sampleBufferLen;
|
size_t sampleBufferLen;
|
||||||
/*float * seekTable;
|
/*float * seekTable;
|
||||||
long seekTableEnd = -1;
|
long seekTableEnd = -1;
|
||||||
int seekPositionFound = 0;*/
|
int seekPositionFound = 0; */
|
||||||
mpd_uint16 bitRate = 0;
|
mpd_uint16 bitRate = 0;
|
||||||
AacBuffer b;
|
AacBuffer b;
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
|
|
||||||
if((totalTime = getAacFloatTotalTime(path)) < 0) return -1;
|
if ((totalTime = getAacFloatTotalTime(path)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(openInputStream(&inStream, path) < 0) return -1;
|
if (openInputStream(&inStream, path) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
initAacBuffer(&inStream,&b,NULL,NULL,NULL);
|
initAacBuffer(&inStream, &b, NULL, NULL, NULL);
|
||||||
|
|
||||||
decoder = faacDecOpen();
|
decoder = faacDecOpen();
|
||||||
|
|
||||||
@ -286,21 +323,22 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
|
#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
|
||||||
config->dontUpSampleImplicitSBR = 0;
|
config->dontUpSampleImplicitSBR = 0;
|
||||||
#endif
|
#endif
|
||||||
faacDecSetConfiguration(decoder,config);
|
faacDecSetConfiguration(decoder, config);
|
||||||
|
|
||||||
fillAacBuffer(&b);
|
fillAacBuffer(&b);
|
||||||
|
|
||||||
#ifdef HAVE_FAAD_BUFLEN_FUNCS
|
#ifdef HAVE_FAAD_BUFLEN_FUNCS
|
||||||
bread = faacDecInit(decoder,b.buffer,b.bytesIntoBuffer,
|
bread = faacDecInit(decoder, b.buffer, b.bytesIntoBuffer,
|
||||||
&sampleRate,&channels);
|
&sampleRate, &channels);
|
||||||
#else
|
#else
|
||||||
bread = faacDecInit(decoder,b.buffer,&sampleRate,&channels);
|
bread = faacDecInit(decoder, b.buffer, &sampleRate, &channels);
|
||||||
#endif
|
#endif
|
||||||
if(bread < 0) {
|
if (bread < 0) {
|
||||||
ERROR("Error not a AAC stream.\n");
|
ERROR("Error not a AAC stream.\n");
|
||||||
faacDecClose(decoder);
|
faacDecClose(decoder);
|
||||||
closeInputStream(b.inStream);
|
closeInputStream(b.inStream);
|
||||||
if(b.buffer) free(b.buffer);
|
if (b.buffer)
|
||||||
|
free(b.buffer);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,36 +348,34 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
|
|
||||||
time = 0.0;
|
time = 0.0;
|
||||||
|
|
||||||
advanceAacBuffer(&b,bread);
|
advanceAacBuffer(&b, bread);
|
||||||
|
|
||||||
while(!eof) {
|
while (!eof) {
|
||||||
fillAacBuffer(&b);
|
fillAacBuffer(&b);
|
||||||
|
|
||||||
if(b.bytesIntoBuffer==0) {
|
if (b.bytesIntoBuffer == 0) {
|
||||||
eof = 1;
|
eof = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_FAAD_BUFLEN_FUNCS
|
#ifdef HAVE_FAAD_BUFLEN_FUNCS
|
||||||
sampleBuffer = faacDecDecode(decoder,&frameInfo,b.buffer,
|
sampleBuffer = faacDecDecode(decoder, &frameInfo, b.buffer,
|
||||||
b.bytesIntoBuffer);
|
b.bytesIntoBuffer);
|
||||||
#else
|
#else
|
||||||
sampleBuffer = faacDecDecode(decoder,&frameInfo,b.buffer);
|
sampleBuffer = faacDecDecode(decoder, &frameInfo, b.buffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(frameInfo.error > 0) {
|
if (frameInfo.error > 0) {
|
||||||
ERROR("error decoding AAC file: %s\n", path);
|
ERROR("error decoding AAC file: %s\n", path);
|
||||||
ERROR("faad2 error: %s\n",
|
ERROR("faad2 error: %s\n",
|
||||||
faacDecGetErrorMessage(frameInfo.error));
|
faacDecGetErrorMessage(frameInfo.error));
|
||||||
eof = 1;
|
eof = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE
|
#ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE
|
||||||
sampleRate = frameInfo.samplerate;
|
sampleRate = frameInfo.samplerate;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(dc->state != DECODE_STATE_DECODE) {
|
if (dc->state != DECODE_STATE_DECODE) {
|
||||||
dc->audioFormat.channels = frameInfo.channels;
|
dc->audioFormat.channels = frameInfo.channels;
|
||||||
dc->audioFormat.sampleRate = sampleRate;
|
dc->audioFormat.sampleRate = sampleRate;
|
||||||
getOutputAudioFormat(&(dc->audioFormat),
|
getOutputAudioFormat(&(dc->audioFormat),
|
||||||
@ -347,27 +383,27 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
advanceAacBuffer(&b,frameInfo.bytesconsumed);
|
advanceAacBuffer(&b, frameInfo.bytesconsumed);
|
||||||
|
|
||||||
sampleCount = (unsigned long)(frameInfo.samples);
|
sampleCount = (unsigned long)(frameInfo.samples);
|
||||||
|
|
||||||
if(sampleCount>0) {
|
if (sampleCount > 0) {
|
||||||
bitRate = frameInfo.bytesconsumed*8.0*
|
bitRate = frameInfo.bytesconsumed * 8.0 *
|
||||||
frameInfo.channels*sampleRate/
|
frameInfo.channels * sampleRate /
|
||||||
frameInfo.samples/1000+0.5;
|
frameInfo.samples / 1000 + 0.5;
|
||||||
time+= (float)(frameInfo.samples)/frameInfo.channels/
|
time +=
|
||||||
|
(float)(frameInfo.samples) / frameInfo.channels /
|
||||||
sampleRate;
|
sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleBufferLen = sampleCount*2;
|
sampleBufferLen = sampleCount * 2;
|
||||||
|
|
||||||
sendDataToOutputBuffer(cb, NULL, dc, 0, sampleBuffer,
|
sendDataToOutputBuffer(cb, NULL, dc, 0, sampleBuffer,
|
||||||
sampleBufferLen, time, bitRate, NULL);
|
sampleBufferLen, time, bitRate, NULL);
|
||||||
if(dc->seek) {
|
if (dc->seek) {
|
||||||
dc->seekError = 1;
|
dc->seekError = 1;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
} else if (dc->stop) {
|
||||||
else if(dc->stop) {
|
|
||||||
eof = 1;
|
eof = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -377,45 +413,48 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
|
|
||||||
faacDecClose(decoder);
|
faacDecClose(decoder);
|
||||||
closeInputStream(b.inStream);
|
closeInputStream(b.inStream);
|
||||||
if(b.buffer) free(b.buffer);
|
if (b.buffer)
|
||||||
|
free(b.buffer);
|
||||||
|
|
||||||
if(dc->state != DECODE_STATE_DECODE) return -1;
|
if (dc->state != DECODE_STATE_DECODE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(dc->seek) {
|
if (dc->seek) {
|
||||||
dc->seekError = 1;
|
dc->seekError = 1;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dc->stop) {
|
if (dc->stop) {
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
}
|
} else
|
||||||
else dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * aacTagDup(char * file) {
|
static MpdTag *aacTagDup(char *file)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
|
MpdTag *ret = NULL;
|
||||||
int time;
|
int time;
|
||||||
|
|
||||||
time = getAacTotalTime(file);
|
time = getAacTotalTime(file);
|
||||||
|
|
||||||
if(time>=0) {
|
if (time >= 0) {
|
||||||
if((ret = id3Dup(file))==NULL) ret = newMpdTag();
|
if ((ret = id3Dup(file)) == NULL)
|
||||||
|
ret = newMpdTag();
|
||||||
ret->time = time;
|
ret->time = time;
|
||||||
}
|
} else {
|
||||||
else {
|
DEBUG("aacTagDup: Failed to get total song time from: %s\n",
|
||||||
DEBUG("aacTagDup: Failed to get total song time from: %s\n", file);
|
file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * aacSuffixes[] = {"aac", NULL};
|
static char *aacSuffixes[] = { "aac", NULL };
|
||||||
|
|
||||||
InputPlugin aacPlugin =
|
InputPlugin aacPlugin = {
|
||||||
{
|
|
||||||
"aac",
|
"aac",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -430,8 +469,7 @@ InputPlugin aacPlugin =
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
InputPlugin aacPlugin =
|
InputPlugin aacPlugin = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -37,34 +37,35 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <audiofile.h>
|
#include <audiofile.h>
|
||||||
|
|
||||||
static int getAudiofileTotalTime(char * file)
|
static int getAudiofileTotalTime(char *file)
|
||||||
{
|
{
|
||||||
int time;
|
int time;
|
||||||
AFfilehandle af_fp = afOpenFile(file, "r", NULL);
|
AFfilehandle af_fp = afOpenFile(file, "r", NULL);
|
||||||
if(af_fp == AF_NULL_FILEHANDLE) {
|
if (af_fp == AF_NULL_FILEHANDLE) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
time = (int)
|
time = (int)
|
||||||
((double)afGetFrameCount(af_fp,AF_DEFAULT_TRACK)
|
((double)afGetFrameCount(af_fp, AF_DEFAULT_TRACK)
|
||||||
/afGetRate(af_fp,AF_DEFAULT_TRACK));
|
/ afGetRate(af_fp, AF_DEFAULT_TRACK));
|
||||||
afCloseFile(af_fp);
|
afCloseFile(af_fp);
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
static int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
|
||||||
|
{
|
||||||
int fs, frame_count;
|
int fs, frame_count;
|
||||||
AFfilehandle af_fp;
|
AFfilehandle af_fp;
|
||||||
int bits;
|
int bits;
|
||||||
mpd_uint16 bitRate;
|
mpd_uint16 bitRate;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if(stat(path, &st) < 0) {
|
if (stat(path, &st) < 0) {
|
||||||
ERROR("failed to stat: %s\n", path);
|
ERROR("failed to stat: %s\n", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
af_fp = afOpenFile(path, "r", NULL);
|
af_fp = afOpenFile(path, "r", NULL);
|
||||||
if(af_fp == AF_NULL_FILEHANDLE) {
|
if (af_fp == AF_NULL_FILEHANDLE) {
|
||||||
ERROR("failed to open: %s\n", path);
|
ERROR("failed to open: %s\n", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -72,14 +73,15 @@ static int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path)
|
|||||||
afGetSampleFormat(af_fp, AF_DEFAULT_TRACK, &fs, &bits);
|
afGetSampleFormat(af_fp, AF_DEFAULT_TRACK, &fs, &bits);
|
||||||
dc->audioFormat.bits = bits;
|
dc->audioFormat.bits = bits;
|
||||||
dc->audioFormat.sampleRate = afGetRate(af_fp, AF_DEFAULT_TRACK);
|
dc->audioFormat.sampleRate = afGetRate(af_fp, AF_DEFAULT_TRACK);
|
||||||
dc->audioFormat.channels = afGetChannels(af_fp,AF_DEFAULT_TRACK);
|
dc->audioFormat.channels = afGetChannels(af_fp, AF_DEFAULT_TRACK);
|
||||||
getOutputAudioFormat(&(dc->audioFormat),&(cb->audioFormat));
|
getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
|
||||||
|
|
||||||
frame_count = afGetFrameCount(af_fp,AF_DEFAULT_TRACK);
|
frame_count = afGetFrameCount(af_fp, AF_DEFAULT_TRACK);
|
||||||
|
|
||||||
dc->totalTime = ((float)frame_count/(float)dc->audioFormat.sampleRate);
|
dc->totalTime =
|
||||||
|
((float)frame_count / (float)dc->audioFormat.sampleRate);
|
||||||
|
|
||||||
bitRate = st.st_size*8.0/dc->totalTime/1000.0+0.5;
|
bitRate = st.st_size * 8.0 / dc->totalTime / 1000.0 + 0.5;
|
||||||
|
|
||||||
if (dc->audioFormat.bits != 8 && dc->audioFormat.bits != 16) {
|
if (dc->audioFormat.bits != 8 && dc->audioFormat.bits != 16) {
|
||||||
ERROR("Only 8 and 16-bit files are supported. %s is %i-bit\n",
|
ERROR("Only 8 and 16-bit files are supported. %s is %i-bit\n",
|
||||||
@ -88,24 +90,27 @@ static int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fs = (int)afGetFrameSize(af_fp, AF_DEFAULT_TRACK,1);
|
fs = (int)afGetFrameSize(af_fp, AF_DEFAULT_TRACK, 1);
|
||||||
|
|
||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
{
|
{
|
||||||
int ret, eof = 0, current = 0;
|
int ret, eof = 0, current = 0;
|
||||||
char chunk[CHUNK_SIZE];
|
char chunk[CHUNK_SIZE];
|
||||||
|
|
||||||
while(!eof) {
|
while (!eof) {
|
||||||
if(dc->seek) {
|
if (dc->seek) {
|
||||||
clearOutputBuffer(cb);
|
clearOutputBuffer(cb);
|
||||||
current = dc->seekWhere *
|
current = dc->seekWhere *
|
||||||
dc->audioFormat.sampleRate;
|
dc->audioFormat.sampleRate;
|
||||||
afSeekFrame(af_fp, AF_DEFAULT_TRACK,current);
|
afSeekFrame(af_fp, AF_DEFAULT_TRACK, current);
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk, CHUNK_SIZE/fs);
|
ret =
|
||||||
if(ret<=0) eof = 1;
|
afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk,
|
||||||
|
CHUNK_SIZE / fs);
|
||||||
|
if (ret <= 0)
|
||||||
|
eof = 1;
|
||||||
else {
|
else {
|
||||||
current += ret;
|
current += ret;
|
||||||
sendDataToOutputBuffer(cb,
|
sendDataToOutputBuffer(cb,
|
||||||
@ -113,12 +118,13 @@ static int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path)
|
|||||||
dc,
|
dc,
|
||||||
1,
|
1,
|
||||||
chunk,
|
chunk,
|
||||||
ret*fs,
|
ret * fs,
|
||||||
(float)current /
|
(float)current /
|
||||||
(float)dc->audioFormat.sampleRate,
|
(float)dc->audioFormat.
|
||||||
bitRate,
|
sampleRate, bitRate,
|
||||||
NULL);
|
NULL);
|
||||||
if(dc->stop) break;
|
if (dc->stop)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,38 +133,40 @@ static int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path)
|
|||||||
/*if(dc->seek) {
|
/*if(dc->seek) {
|
||||||
dc->seekError = 1;
|
dc->seekError = 1;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}*/
|
} */
|
||||||
|
|
||||||
if(dc->stop) {
|
if (dc->stop) {
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
}
|
} else
|
||||||
else dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
}
|
}
|
||||||
afCloseFile(af_fp);
|
afCloseFile(af_fp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * audiofileTagDup(char * file) {
|
static MpdTag *audiofileTagDup(char *file)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
|
MpdTag *ret = NULL;
|
||||||
int time = getAudiofileTotalTime(file);
|
int time = getAudiofileTotalTime(file);
|
||||||
|
|
||||||
if (time>=0) {
|
if (time >= 0) {
|
||||||
if(!ret) ret = newMpdTag();
|
if (!ret)
|
||||||
|
ret = newMpdTag();
|
||||||
ret->time = time;
|
ret->time = time;
|
||||||
}
|
} else {
|
||||||
else {
|
DEBUG
|
||||||
DEBUG("audiofileTagDup: Failed to get total song time from: %s\n", file);
|
("audiofileTagDup: Failed to get total song time from: %s\n",
|
||||||
|
file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * audiofileSuffixes[] = {"wav", "au", "aiff", "aif", NULL};
|
static char *audiofileSuffixes[] = { "wav", "au", "aiff", "aif", NULL };
|
||||||
|
|
||||||
InputPlugin audiofilePlugin =
|
InputPlugin audiofilePlugin = {
|
||||||
{
|
|
||||||
"audiofile",
|
"audiofile",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -173,8 +181,7 @@ InputPlugin audiofilePlugin =
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
InputPlugin audiofilePlugin =
|
InputPlugin audiofilePlugin = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -43,111 +43,126 @@ static void flacError(const FLAC__SeekableStreamDecoder *,
|
|||||||
static void flacPrintErroredState(FLAC__SeekableStreamDecoderState state);
|
static void flacPrintErroredState(FLAC__SeekableStreamDecoderState state);
|
||||||
static void flacMetadata(const FLAC__SeekableStreamDecoder *,
|
static void flacMetadata(const FLAC__SeekableStreamDecoder *,
|
||||||
const FLAC__StreamMetadata *, void *);
|
const FLAC__StreamMetadata *, void *);
|
||||||
static FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__SeekableStreamDecoder *,
|
static FLAC__StreamDecoderWriteStatus flacWrite(const
|
||||||
const FLAC__Frame *, const FLAC__int32 * const buf[], void *);
|
FLAC__SeekableStreamDecoder *,
|
||||||
static FLAC__SeekableStreamDecoderReadStatus flacRead(
|
const FLAC__Frame *,
|
||||||
const FLAC__SeekableStreamDecoder *, FLAC__byte buf[],
|
const FLAC__int32 * const buf[],
|
||||||
|
void *);
|
||||||
|
static FLAC__SeekableStreamDecoderReadStatus flacRead(const
|
||||||
|
FLAC__SeekableStreamDecoder
|
||||||
|
*, FLAC__byte buf[],
|
||||||
unsigned *, void *);
|
unsigned *, void *);
|
||||||
static FLAC__SeekableStreamDecoderSeekStatus flacSeek(
|
static FLAC__SeekableStreamDecoderSeekStatus flacSeek(const
|
||||||
const FLAC__SeekableStreamDecoder *, FLAC__uint64, void *);
|
FLAC__SeekableStreamDecoder
|
||||||
static FLAC__SeekableStreamDecoderTellStatus flacTell(
|
*, FLAC__uint64, void *);
|
||||||
const FLAC__SeekableStreamDecoder *, FLAC__uint64 *, void *);
|
static FLAC__SeekableStreamDecoderTellStatus flacTell(const
|
||||||
static FLAC__SeekableStreamDecoderLengthStatus flacLength(
|
FLAC__SeekableStreamDecoder
|
||||||
const FLAC__SeekableStreamDecoder *, FLAC__uint64 *, void *);
|
*, FLAC__uint64 *,
|
||||||
|
void *);
|
||||||
|
static FLAC__SeekableStreamDecoderLengthStatus flacLength(const
|
||||||
|
FLAC__SeekableStreamDecoder
|
||||||
|
*, FLAC__uint64 *,
|
||||||
|
void *);
|
||||||
static FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder *, void *);
|
static FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder *, void *);
|
||||||
|
|
||||||
static int flac_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
|
static int flac_decode(OutputBuffer * cb, DecoderControl * dc,
|
||||||
|
InputStream * inStream)
|
||||||
{
|
{
|
||||||
FLAC__SeekableStreamDecoder * flacDec = NULL;
|
FLAC__SeekableStreamDecoder *flacDec = NULL;
|
||||||
FlacData data;
|
FlacData data;
|
||||||
int status = 1;
|
int status = 1;
|
||||||
int ret =0;
|
int ret = 0;
|
||||||
|
|
||||||
init_FlacData(&data, cb, dc, inStream);
|
init_FlacData(&data, cb, dc, inStream);
|
||||||
|
|
||||||
if(!(flacDec = FLAC__seekable_stream_decoder_new())) {
|
if (!(flacDec = FLAC__seekable_stream_decoder_new())) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
/*status&=FLAC__file_decoder_set_md5_checking(flacDec,1);*/
|
/*status&=FLAC__file_decoder_set_md5_checking(flacDec,1); */
|
||||||
status&=FLAC__seekable_stream_decoder_set_read_callback(flacDec,
|
status &= FLAC__seekable_stream_decoder_set_read_callback(flacDec,
|
||||||
flacRead);
|
flacRead);
|
||||||
status&=FLAC__seekable_stream_decoder_set_seek_callback(flacDec,
|
status &= FLAC__seekable_stream_decoder_set_seek_callback(flacDec,
|
||||||
flacSeek);
|
flacSeek);
|
||||||
status&=FLAC__seekable_stream_decoder_set_tell_callback(flacDec,
|
status &= FLAC__seekable_stream_decoder_set_tell_callback(flacDec,
|
||||||
flacTell);
|
flacTell);
|
||||||
status&=FLAC__seekable_stream_decoder_set_length_callback(flacDec,
|
status &= FLAC__seekable_stream_decoder_set_length_callback(flacDec,
|
||||||
flacLength);
|
flacLength);
|
||||||
status&=FLAC__seekable_stream_decoder_set_eof_callback(flacDec,flacEOF);
|
status &=
|
||||||
status&=FLAC__seekable_stream_decoder_set_write_callback(flacDec,
|
FLAC__seekable_stream_decoder_set_eof_callback(flacDec, flacEOF);
|
||||||
|
status &=
|
||||||
|
FLAC__seekable_stream_decoder_set_write_callback(flacDec,
|
||||||
flacWrite);
|
flacWrite);
|
||||||
status&=FLAC__seekable_stream_decoder_set_metadata_callback(flacDec,
|
status &=
|
||||||
|
FLAC__seekable_stream_decoder_set_metadata_callback(flacDec,
|
||||||
flacMetadata);
|
flacMetadata);
|
||||||
status&=FLAC__seekable_stream_decoder_set_metadata_respond(flacDec,
|
status &=
|
||||||
|
FLAC__seekable_stream_decoder_set_metadata_respond(flacDec,
|
||||||
FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||||
status&=FLAC__seekable_stream_decoder_set_error_callback(flacDec,
|
status &=
|
||||||
|
FLAC__seekable_stream_decoder_set_error_callback(flacDec,
|
||||||
flacError);
|
flacError);
|
||||||
status&=FLAC__seekable_stream_decoder_set_client_data(flacDec,
|
status &=
|
||||||
|
FLAC__seekable_stream_decoder_set_client_data(flacDec,
|
||||||
(void *)&data);
|
(void *)&data);
|
||||||
if(!status) {
|
if (!status) {
|
||||||
ERROR("flac problem before init()\n");
|
ERROR("flac problem before init()\n");
|
||||||
flacPrintErroredState(
|
flacPrintErroredState(FLAC__seekable_stream_decoder_get_state
|
||||||
FLAC__seekable_stream_decoder_get_state(flacDec));
|
(flacDec));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(FLAC__seekable_stream_decoder_init(flacDec)!=
|
if (FLAC__seekable_stream_decoder_init(flacDec) !=
|
||||||
FLAC__SEEKABLE_STREAM_DECODER_OK)
|
FLAC__SEEKABLE_STREAM_DECODER_OK) {
|
||||||
{
|
|
||||||
ERROR("flac problem doing init()\n");
|
ERROR("flac problem doing init()\n");
|
||||||
flacPrintErroredState(
|
flacPrintErroredState(FLAC__seekable_stream_decoder_get_state
|
||||||
FLAC__seekable_stream_decoder_get_state(flacDec));
|
(flacDec));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!FLAC__seekable_stream_decoder_process_until_end_of_metadata(flacDec)) {
|
if (!FLAC__seekable_stream_decoder_process_until_end_of_metadata
|
||||||
|
(flacDec)) {
|
||||||
ERROR("flac problem reading metadata\n");
|
ERROR("flac problem reading metadata\n");
|
||||||
flacPrintErroredState(
|
flacPrintErroredState(FLAC__seekable_stream_decoder_get_state
|
||||||
FLAC__seekable_stream_decoder_get_state(flacDec));
|
(flacDec));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
FLAC__seekable_stream_decoder_process_single(flacDec);
|
FLAC__seekable_stream_decoder_process_single(flacDec);
|
||||||
if(FLAC__seekable_stream_decoder_get_state(flacDec)!=
|
if (FLAC__seekable_stream_decoder_get_state(flacDec) !=
|
||||||
FLAC__SEEKABLE_STREAM_DECODER_OK)
|
FLAC__SEEKABLE_STREAM_DECODER_OK) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(dc->seek) {
|
if (dc->seek) {
|
||||||
FLAC__uint64 sampleToSeek = dc->seekWhere*
|
FLAC__uint64 sampleToSeek = dc->seekWhere *
|
||||||
dc->audioFormat.sampleRate+0.5;
|
dc->audioFormat.sampleRate + 0.5;
|
||||||
if(FLAC__seekable_stream_decoder_seek_absolute(flacDec,
|
if (FLAC__seekable_stream_decoder_seek_absolute(flacDec,
|
||||||
sampleToSeek))
|
sampleToSeek))
|
||||||
{
|
{
|
||||||
clearOutputBuffer(cb);
|
clearOutputBuffer(cb);
|
||||||
data.time = ((float)sampleToSeek)/
|
data.time = ((float)sampleToSeek) /
|
||||||
dc->audioFormat.sampleRate;
|
dc->audioFormat.sampleRate;
|
||||||
data.position = 0;
|
data.position = 0;
|
||||||
}
|
} else
|
||||||
else dc->seekError = 1;
|
dc->seekError = 1;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* I don't think we need this bit here! -shank */
|
/* I don't think we need this bit here! -shank */
|
||||||
/*FLAC__file_decoder_process_until_end_of_file(flacDec);*/
|
/*FLAC__file_decoder_process_until_end_of_file(flacDec); */
|
||||||
if(!dc->stop) {
|
if (!dc->stop) {
|
||||||
flacPrintErroredState(
|
flacPrintErroredState(FLAC__seekable_stream_decoder_get_state
|
||||||
FLAC__seekable_stream_decoder_get_state(flacDec));
|
(flacDec));
|
||||||
FLAC__seekable_stream_decoder_finish(flacDec);
|
FLAC__seekable_stream_decoder_finish(flacDec);
|
||||||
}
|
}
|
||||||
/* send last little bit */
|
/* send last little bit */
|
||||||
if(data.chunk_length>0 && !dc->stop) {
|
if (data.chunk_length > 0 && !dc->stop) {
|
||||||
flacSendChunk(&data);
|
flacSendChunk(&data);
|
||||||
flushOutputBuffer(data.cb);
|
flushOutputBuffer(data.cb);
|
||||||
}
|
}
|
||||||
@ -160,24 +175,30 @@ static int flac_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inS
|
|||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if(data.replayGainInfo) freeReplayGainInfo(data.replayGainInfo);
|
if (data.replayGainInfo)
|
||||||
|
freeReplayGainInfo(data.replayGainInfo);
|
||||||
|
|
||||||
if(flacDec) FLAC__seekable_stream_decoder_delete(flacDec);
|
if (flacDec)
|
||||||
|
FLAC__seekable_stream_decoder_delete(flacDec);
|
||||||
|
|
||||||
closeInputStream(inStream);
|
closeInputStream(inStream);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__SeekableStreamDecoderReadStatus flacRead(
|
static FLAC__SeekableStreamDecoderReadStatus flacRead(const
|
||||||
const FLAC__SeekableStreamDecoder * flacDec, FLAC__byte buf[],
|
FLAC__SeekableStreamDecoder
|
||||||
unsigned * bytes, void * fdata) {
|
* flacDec,
|
||||||
FlacData * data = (FlacData *) fdata;
|
FLAC__byte buf[],
|
||||||
|
unsigned *bytes,
|
||||||
|
void *fdata)
|
||||||
|
{
|
||||||
|
FlacData *data = (FlacData *) fdata;
|
||||||
size_t r;
|
size_t r;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
r = readFromInputStream(data->inStream,(void *)buf,1,*bytes);
|
r = readFromInputStream(data->inStream, (void *)buf, 1, *bytes);
|
||||||
if (r == 0 && !inputStreamAtEOF(data->inStream) &&
|
if (r == 0 && !inputStreamAtEOF(data->inStream) &&
|
||||||
!data->dc->stop)
|
!data->dc->stop)
|
||||||
my_usleep(10000);
|
my_usleep(10000);
|
||||||
@ -186,64 +207,72 @@ static FLAC__SeekableStreamDecoderReadStatus flacRead(
|
|||||||
}
|
}
|
||||||
*bytes = r;
|
*bytes = r;
|
||||||
|
|
||||||
if (*bytes==0 && !inputStreamAtEOF(data->inStream) && !data->dc->stop)
|
if (*bytes == 0 && !inputStreamAtEOF(data->inStream) && !data->dc->stop)
|
||||||
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
|
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
|
||||||
|
|
||||||
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
|
return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__SeekableStreamDecoderSeekStatus flacSeek(
|
static FLAC__SeekableStreamDecoderSeekStatus flacSeek(const
|
||||||
const FLAC__SeekableStreamDecoder * flacDec,
|
FLAC__SeekableStreamDecoder
|
||||||
FLAC__uint64 offset, void * fdata)
|
* flacDec,
|
||||||
|
FLAC__uint64 offset,
|
||||||
|
void *fdata)
|
||||||
{
|
{
|
||||||
FlacData * data = (FlacData *) fdata;
|
FlacData *data = (FlacData *) fdata;
|
||||||
|
|
||||||
if(seekInputStream(data->inStream,offset,SEEK_SET)<0) {
|
if (seekInputStream(data->inStream, offset, SEEK_SET) < 0) {
|
||||||
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
|
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
|
return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__SeekableStreamDecoderTellStatus flacTell(
|
static FLAC__SeekableStreamDecoderTellStatus flacTell(const
|
||||||
const FLAC__SeekableStreamDecoder * flacDec,
|
FLAC__SeekableStreamDecoder
|
||||||
FLAC__uint64 * offset, void * fdata)
|
* flacDec,
|
||||||
|
FLAC__uint64 * offset,
|
||||||
|
void *fdata)
|
||||||
{
|
{
|
||||||
FlacData * data = (FlacData *) fdata;
|
FlacData *data = (FlacData *) fdata;
|
||||||
|
|
||||||
*offset = (long)(data->inStream->offset);
|
*offset = (long)(data->inStream->offset);
|
||||||
|
|
||||||
return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
|
return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__SeekableStreamDecoderLengthStatus flacLength(
|
static FLAC__SeekableStreamDecoderLengthStatus flacLength(const
|
||||||
const FLAC__SeekableStreamDecoder * flacDec,
|
FLAC__SeekableStreamDecoder
|
||||||
FLAC__uint64 * length, void * fdata)
|
* flacDec,
|
||||||
|
FLAC__uint64 * length,
|
||||||
|
void *fdata)
|
||||||
{
|
{
|
||||||
FlacData * data = (FlacData *) fdata;
|
FlacData *data = (FlacData *) fdata;
|
||||||
|
|
||||||
*length = (size_t)(data->inStream->size);
|
*length = (size_t) (data->inStream->size);
|
||||||
|
|
||||||
return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
|
return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder * flacDec, void * fdata) {
|
static FLAC__bool flacEOF(const FLAC__SeekableStreamDecoder * flacDec,
|
||||||
FlacData * data = (FlacData *) fdata;
|
void *fdata)
|
||||||
|
{
|
||||||
|
FlacData *data = (FlacData *) fdata;
|
||||||
|
|
||||||
if (inputStreamAtEOF(data->inStream) == 1)
|
if (inputStreamAtEOF(data->inStream) == 1)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flacError(const FLAC__SeekableStreamDecoder *dec,
|
static void flacError(const FLAC__SeekableStreamDecoder * dec,
|
||||||
FLAC__StreamDecoderErrorStatus status, void *fdata)
|
FLAC__StreamDecoderErrorStatus status, void *fdata)
|
||||||
{
|
{
|
||||||
flac_error_common_cb("flac",status,(FlacData *) fdata);
|
flac_error_common_cb("flac", status, (FlacData *) fdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flacPrintErroredState(FLAC__SeekableStreamDecoderState state)
|
static void flacPrintErroredState(FLAC__SeekableStreamDecoderState state)
|
||||||
{
|
{
|
||||||
switch(state) {
|
switch (state) {
|
||||||
case FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
|
case FLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
|
||||||
ERROR("flac allocation error\n");
|
ERROR("flac allocation error\n");
|
||||||
break;
|
break;
|
||||||
@ -272,48 +301,53 @@ static void flacPrintErroredState(FLAC__SeekableStreamDecoderState state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flacMetadata(const FLAC__SeekableStreamDecoder *dec,
|
static void flacMetadata(const FLAC__SeekableStreamDecoder * dec,
|
||||||
const FLAC__StreamMetadata *block, void *vdata)
|
const FLAC__StreamMetadata * block, void *vdata)
|
||||||
{
|
{
|
||||||
flac_metadata_common_cb(block, (FlacData *)vdata);
|
flac_metadata_common_cb(block, (FlacData *) vdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__SeekableStreamDecoder *dec,
|
static FLAC__StreamDecoderWriteStatus flacWrite(const
|
||||||
const FLAC__Frame *frame, const FLAC__int32 * const buf[],
|
FLAC__SeekableStreamDecoder *
|
||||||
void * vdata)
|
dec, const FLAC__Frame * frame,
|
||||||
|
const FLAC__int32 * const buf[],
|
||||||
|
void *vdata)
|
||||||
{
|
{
|
||||||
FlacData * data = (FlacData *)vdata;
|
FlacData *data = (FlacData *) vdata;
|
||||||
FLAC__uint32 samples = frame->header.blocksize;
|
FLAC__uint32 samples = frame->header.blocksize;
|
||||||
FLAC__uint16 u16;
|
FLAC__uint16 u16;
|
||||||
unsigned char * uc;
|
unsigned char *uc;
|
||||||
int c_samp, c_chan, d_samp;
|
int c_samp, c_chan, d_samp;
|
||||||
int i;
|
int i;
|
||||||
float timeChange;
|
float timeChange;
|
||||||
FLAC__uint64 newPosition = 0;
|
FLAC__uint64 newPosition = 0;
|
||||||
|
|
||||||
timeChange = ((float)samples)/frame->header.sample_rate;
|
timeChange = ((float)samples) / frame->header.sample_rate;
|
||||||
data->time+= timeChange;
|
data->time += timeChange;
|
||||||
|
|
||||||
FLAC__seekable_stream_decoder_get_decode_position(dec,&newPosition);
|
FLAC__seekable_stream_decoder_get_decode_position(dec, &newPosition);
|
||||||
if(data->position) {
|
if (data->position) {
|
||||||
data->bitRate = ((newPosition-data->position)*8.0/timeChange)
|
data->bitRate =
|
||||||
/1000+0.5;
|
((newPosition - data->position) * 8.0 / timeChange)
|
||||||
|
/ 1000 + 0.5;
|
||||||
}
|
}
|
||||||
data->position = newPosition;
|
data->position = newPosition;
|
||||||
|
|
||||||
for(c_samp = d_samp = 0; c_samp < frame->header.blocksize; c_samp++) {
|
for (c_samp = d_samp = 0; c_samp < frame->header.blocksize; c_samp++) {
|
||||||
for(c_chan = 0; c_chan < frame->header.channels;
|
for (c_chan = 0; c_chan < frame->header.channels;
|
||||||
c_chan++, d_samp++) {
|
c_chan++, d_samp++) {
|
||||||
u16 = buf[c_chan][c_samp];
|
u16 = buf[c_chan][c_samp];
|
||||||
uc = (unsigned char *)&u16;
|
uc = (unsigned char *)&u16;
|
||||||
for(i=0;i<(data->dc->audioFormat.bits/8);i++) {
|
for (i = 0; i < (data->dc->audioFormat.bits / 8); i++) {
|
||||||
if(data->chunk_length>=FLAC_CHUNK_SIZE) {
|
if (data->chunk_length >= FLAC_CHUNK_SIZE) {
|
||||||
if(flacSendChunk(data)<0) {
|
if (flacSendChunk(data) < 0) {
|
||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
return
|
||||||
|
FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
}
|
}
|
||||||
data->chunk_length = 0;
|
data->chunk_length = 0;
|
||||||
if(data->dc->seek) {
|
if (data->dc->seek) {
|
||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
return
|
||||||
|
FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data->chunk[data->chunk_length++] = *(uc++);
|
data->chunk[data->chunk_length++] = *(uc++);
|
||||||
@ -324,27 +358,35 @@ static FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__SeekableStreamDecode
|
|||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * flacMetadataDup(char * file, int * vorbisCommentFound) {
|
static MpdTag *flacMetadataDup(char *file, int *vorbisCommentFound)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
FLAC__Metadata_SimpleIterator * it;
|
MpdTag *ret = NULL;
|
||||||
FLAC__StreamMetadata * block = NULL;
|
FLAC__Metadata_SimpleIterator *it;
|
||||||
|
FLAC__StreamMetadata *block = NULL;
|
||||||
|
|
||||||
*vorbisCommentFound = 0;
|
*vorbisCommentFound = 0;
|
||||||
|
|
||||||
it = FLAC__metadata_simple_iterator_new();
|
it = FLAC__metadata_simple_iterator_new();
|
||||||
if(!FLAC__metadata_simple_iterator_init(it, file ,1,0)) {
|
if (!FLAC__metadata_simple_iterator_init(it, file, 1, 0)) {
|
||||||
switch(FLAC__metadata_simple_iterator_status(it)) {
|
switch (FLAC__metadata_simple_iterator_status(it)) {
|
||||||
case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
|
case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
|
||||||
DEBUG("flacMetadataDup: Reading '%s' metadata gave the following error: Illegal Input\n",file);
|
DEBUG
|
||||||
|
("flacMetadataDup: Reading '%s' metadata gave the following error: Illegal Input\n",
|
||||||
|
file);
|
||||||
break;
|
break;
|
||||||
case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
|
case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
|
||||||
DEBUG("flacMetadataDup: Reading '%s' metadata gave the following error: Error Opening File\n",file);
|
DEBUG
|
||||||
|
("flacMetadataDup: Reading '%s' metadata gave the following error: Error Opening File\n",
|
||||||
|
file);
|
||||||
break;
|
break;
|
||||||
case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
|
case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
|
||||||
DEBUG("flacMetadataDup: Reading '%s' metadata gave the following error: Not A Flac File\n",file);
|
DEBUG
|
||||||
|
("flacMetadataDup: Reading '%s' metadata gave the following error: Not A Flac File\n",
|
||||||
|
file);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DEBUG("flacMetadataDup: Reading '%s' metadata failed\n",file);
|
DEBUG("flacMetadataDup: Reading '%s' metadata failed\n",
|
||||||
|
file);
|
||||||
}
|
}
|
||||||
FLAC__metadata_simple_iterator_delete(it);
|
FLAC__metadata_simple_iterator_delete(it);
|
||||||
return ret;
|
return ret;
|
||||||
@ -352,38 +394,41 @@ static MpdTag * flacMetadataDup(char * file, int * vorbisCommentFound) {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
block = FLAC__metadata_simple_iterator_get_block(it);
|
block = FLAC__metadata_simple_iterator_get_block(it);
|
||||||
if(!block) break;
|
if (!block)
|
||||||
if(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
break;
|
||||||
|
if (block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
|
||||||
ret = copyVorbisCommentBlockToMpdTag(block, ret);
|
ret = copyVorbisCommentBlockToMpdTag(block, ret);
|
||||||
|
|
||||||
if(ret) *vorbisCommentFound = 1;
|
if (ret)
|
||||||
}
|
*vorbisCommentFound = 1;
|
||||||
else if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
|
} else if (block->type == FLAC__METADATA_TYPE_STREAMINFO) {
|
||||||
if(!ret) ret = newMpdTag();
|
if (!ret)
|
||||||
|
ret = newMpdTag();
|
||||||
ret->time = ((float)block->data.stream_info.
|
ret->time = ((float)block->data.stream_info.
|
||||||
total_samples) /
|
total_samples) /
|
||||||
block->data.stream_info.sample_rate +
|
block->data.stream_info.sample_rate + 0.5;
|
||||||
0.5;
|
|
||||||
}
|
}
|
||||||
FLAC__metadata_object_delete(block);
|
FLAC__metadata_object_delete(block);
|
||||||
} while(FLAC__metadata_simple_iterator_next(it));
|
} while (FLAC__metadata_simple_iterator_next(it));
|
||||||
|
|
||||||
FLAC__metadata_simple_iterator_delete(it);
|
FLAC__metadata_simple_iterator_delete(it);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * flacTagDup(char * file) {
|
static MpdTag *flacTagDup(char *file)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
|
MpdTag *ret = NULL;
|
||||||
int foundVorbisComment = 0;
|
int foundVorbisComment = 0;
|
||||||
|
|
||||||
ret = flacMetadataDup(file, &foundVorbisComment);
|
ret = flacMetadataDup(file, &foundVorbisComment);
|
||||||
if(!ret) {
|
if (!ret) {
|
||||||
DEBUG("flacTagDup: Failed to grab information from: %s\n", file);
|
DEBUG("flacTagDup: Failed to grab information from: %s\n",
|
||||||
|
file);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(!foundVorbisComment) {
|
if (!foundVorbisComment) {
|
||||||
MpdTag * temp = id3Dup(file);
|
MpdTag *temp = id3Dup(file);
|
||||||
if(temp) {
|
if (temp) {
|
||||||
temp->time = ret->time;
|
temp->time = ret->time;
|
||||||
freeMpdTag(ret);
|
freeMpdTag(ret);
|
||||||
ret = temp;
|
ret = temp;
|
||||||
@ -393,11 +438,10 @@ static MpdTag * flacTagDup(char * file) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * flacSuffixes[] = {"flac", NULL};
|
static char *flacSuffixes[] = { "flac", NULL };
|
||||||
static char * flac_mime_types[] = {"application/x-flac", NULL};
|
static char *flac_mime_types[] = { "application/x-flac", NULL };
|
||||||
|
|
||||||
InputPlugin flacPlugin =
|
InputPlugin flacPlugin = {
|
||||||
{
|
|
||||||
"flac",
|
"flac",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -412,8 +456,7 @@ InputPlugin flacPlugin =
|
|||||||
|
|
||||||
#else /* !HAVE_FLAC */
|
#else /* !HAVE_FLAC */
|
||||||
|
|
||||||
InputPlugin flacPlugin =
|
InputPlugin flacPlugin = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -39,23 +39,26 @@
|
|||||||
|
|
||||||
#define MIKMOD_FRAME_SIZE 4096
|
#define MIKMOD_FRAME_SIZE 4096
|
||||||
|
|
||||||
static BOOL mod_mpd_Init(void) {
|
static BOOL mod_mpd_Init(void)
|
||||||
|
{
|
||||||
return VC_Init();
|
return VC_Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mod_mpd_Exit(void) {
|
static void mod_mpd_Exit(void)
|
||||||
|
{
|
||||||
VC_Exit();
|
VC_Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mod_mpd_Update(void) {
|
static void mod_mpd_Update(void)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static BOOL mod_mpd_IsThere(void) {
|
static BOOL mod_mpd_IsThere(void)
|
||||||
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MDRIVER drv_mpd =
|
static MDRIVER drv_mpd = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
"MPD",
|
"MPD",
|
||||||
"MPD Output Driver v0.1",
|
"MPD Output Driver v0.1",
|
||||||
@ -92,10 +95,12 @@ static MDRIVER drv_mpd =
|
|||||||
static int mod_mikModInitiated = 0;
|
static int mod_mikModInitiated = 0;
|
||||||
static int mod_mikModInitError = 0;
|
static int mod_mikModInitError = 0;
|
||||||
|
|
||||||
static int mod_initMikMod(void) {
|
static int mod_initMikMod(void)
|
||||||
if(mod_mikModInitError) return -1;
|
{
|
||||||
|
if (mod_mikModInitError)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(!mod_mikModInitiated) {
|
if (!mod_mikModInitiated) {
|
||||||
mod_mikModInitiated = 1;
|
mod_mikModInitiated = 1;
|
||||||
|
|
||||||
md_device = 0;
|
md_device = 0;
|
||||||
@ -110,7 +115,7 @@ static int mod_initMikMod(void) {
|
|||||||
md_mode = (DMODE_SOFT_MUSIC | DMODE_INTERP | DMODE_STEREO |
|
md_mode = (DMODE_SOFT_MUSIC | DMODE_INTERP | DMODE_STEREO |
|
||||||
DMODE_16BITS);
|
DMODE_16BITS);
|
||||||
|
|
||||||
if(MikMod_Init("")) {
|
if (MikMod_Init("")) {
|
||||||
ERROR("Could not init MikMod: %s\n",
|
ERROR("Could not init MikMod: %s\n",
|
||||||
MikMod_strerror(MikMod_errno));
|
MikMod_strerror(MikMod_errno));
|
||||||
mod_mikModInitError = 1;
|
mod_mikModInitError = 1;
|
||||||
@ -120,20 +125,23 @@ static int mod_initMikMod(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mod_finishMikMod(void) {
|
static void mod_finishMikMod(void)
|
||||||
|
{
|
||||||
MikMod_Exit();
|
MikMod_Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct _mod_Data {
|
typedef struct _mod_Data {
|
||||||
MODULE * moduleHandle;
|
MODULE *moduleHandle;
|
||||||
SBYTE * audio_buffer;
|
SBYTE *audio_buffer;
|
||||||
} mod_Data;
|
} mod_Data;
|
||||||
|
|
||||||
static mod_Data * mod_open(char * path) {
|
static mod_Data *mod_open(char *path)
|
||||||
MODULE * moduleHandle;
|
{
|
||||||
mod_Data * data;
|
MODULE *moduleHandle;
|
||||||
|
mod_Data *data;
|
||||||
|
|
||||||
if(!(moduleHandle = Player_Load(path, 128, 0))) return NULL;
|
if (!(moduleHandle = Player_Load(path, 128, 0)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
data = malloc(sizeof(mod_Data));
|
data = malloc(sizeof(mod_Data));
|
||||||
|
|
||||||
@ -145,22 +153,25 @@ static mod_Data * mod_open(char * path) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mod_close(mod_Data * data) {
|
static void mod_close(mod_Data * data)
|
||||||
|
{
|
||||||
Player_Stop();
|
Player_Stop();
|
||||||
Player_Free(data->moduleHandle);
|
Player_Free(data->moduleHandle);
|
||||||
free(data->audio_buffer);
|
free(data->audio_buffer);
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mod_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
static int mod_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
|
||||||
mod_Data * data;
|
{
|
||||||
|
mod_Data *data;
|
||||||
float time = 0.0;
|
float time = 0.0;
|
||||||
int ret;
|
int ret;
|
||||||
float secPerByte;
|
float secPerByte;
|
||||||
|
|
||||||
if(mod_initMikMod() < 0) return -1;
|
if (mod_initMikMod() < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(!(data = mod_open(path))) {
|
if (!(data = mod_open(path))) {
|
||||||
ERROR("failed to open mod: %s\n", path);
|
ERROR("failed to open mod: %s\n", path);
|
||||||
MikMod_Exit();
|
MikMod_Exit();
|
||||||
return -1;
|
return -1;
|
||||||
@ -169,24 +180,27 @@ static int mod_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
dc->audioFormat.bits = 16;
|
dc->audioFormat.bits = 16;
|
||||||
dc->audioFormat.sampleRate = 44100;
|
dc->audioFormat.sampleRate = 44100;
|
||||||
dc->audioFormat.channels = 2;
|
dc->audioFormat.channels = 2;
|
||||||
getOutputAudioFormat(&(dc->audioFormat),&(cb->audioFormat));
|
getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
|
||||||
|
|
||||||
secPerByte = 1.0/((dc->audioFormat.bits*dc->audioFormat.channels/8.0)*
|
secPerByte =
|
||||||
|
1.0 / ((dc->audioFormat.bits * dc->audioFormat.channels / 8.0) *
|
||||||
(float)dc->audioFormat.sampleRate);
|
(float)dc->audioFormat.sampleRate);
|
||||||
|
|
||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
while(1) {
|
while (1) {
|
||||||
if(dc->seek) {
|
if (dc->seek) {
|
||||||
dc->seekError = 1;
|
dc->seekError = 1;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dc->stop) break;
|
if (dc->stop)
|
||||||
|
break;
|
||||||
|
|
||||||
if(!Player_Active()) break;
|
if (!Player_Active())
|
||||||
|
break;
|
||||||
|
|
||||||
ret = VC_WriteBytes(data->audio_buffer, MIKMOD_FRAME_SIZE);
|
ret = VC_WriteBytes(data->audio_buffer, MIKMOD_FRAME_SIZE);
|
||||||
time += ret*secPerByte;
|
time += ret * secPerByte;
|
||||||
sendDataToOutputBuffer(cb, NULL, dc, 0,
|
sendDataToOutputBuffer(cb, NULL, dc, 0,
|
||||||
(char *)data->audio_buffer, ret, time,
|
(char *)data->audio_buffer, ret, time,
|
||||||
0, NULL);
|
0, NULL);
|
||||||
@ -198,27 +212,28 @@ static int mod_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
|
|
||||||
MikMod_Exit();
|
MikMod_Exit();
|
||||||
|
|
||||||
if(dc->stop) {
|
if (dc->stop) {
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
}
|
} else
|
||||||
else dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * modTagDup(char * file) {
|
static MpdTag *modTagDup(char *file)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
MODULE * moduleHandle;
|
MpdTag *ret = NULL;
|
||||||
char * title;
|
MODULE *moduleHandle;
|
||||||
|
char *title;
|
||||||
|
|
||||||
if(mod_initMikMod() < 0) {
|
if (mod_initMikMod() < 0) {
|
||||||
DEBUG("modTagDup: Failed to initialize MikMod\n");
|
DEBUG("modTagDup: Failed to initialize MikMod\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(moduleHandle = Player_Load(file, 128, 0))) {
|
if (!(moduleHandle = Player_Load(file, 128, 0))) {
|
||||||
DEBUG("modTagDup: Failed to open file: %s\n",file);
|
DEBUG("modTagDup: Failed to open file: %s\n", file);
|
||||||
MikMod_Exit();
|
MikMod_Exit();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -229,14 +244,15 @@ static MpdTag * modTagDup(char * file) {
|
|||||||
|
|
||||||
ret->time = 0;
|
ret->time = 0;
|
||||||
title = strdup(Player_LoadTitle(file));
|
title = strdup(Player_LoadTitle(file));
|
||||||
if(title) addItemToMpdTag(ret, TAG_ITEM_TITLE, title);
|
if (title)
|
||||||
|
addItemToMpdTag(ret, TAG_ITEM_TITLE, title);
|
||||||
|
|
||||||
MikMod_Exit();
|
MikMod_Exit();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * modSuffixes[] = {"amf",
|
static char *modSuffixes[] = { "amf",
|
||||||
"dsm",
|
"dsm",
|
||||||
"far",
|
"far",
|
||||||
"gdm",
|
"gdm",
|
||||||
@ -251,10 +267,10 @@ static char * modSuffixes[] = {"amf",
|
|||||||
"ult",
|
"ult",
|
||||||
"uni",
|
"uni",
|
||||||
"xm",
|
"xm",
|
||||||
NULL};
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
InputPlugin modPlugin =
|
InputPlugin modPlugin = {
|
||||||
{
|
|
||||||
"mod",
|
"mod",
|
||||||
NULL,
|
NULL,
|
||||||
mod_finishMikMod,
|
mod_finishMikMod,
|
||||||
@ -269,8 +285,7 @@ InputPlugin modPlugin =
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
InputPlugin modPlugin =
|
InputPlugin modPlugin = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,8 @@
|
|||||||
|
|
||||||
/* all code here is either based on or copied from FAAD2's frontend code */
|
/* all code here is either based on or copied from FAAD2's frontend code */
|
||||||
|
|
||||||
static int mp4_getAACTrack(mp4ff_t *infile) {
|
static int mp4_getAACTrack(mp4ff_t * infile)
|
||||||
|
{
|
||||||
/* find AAC track */
|
/* find AAC track */
|
||||||
int i, rc;
|
int i, rc;
|
||||||
int numTracks = mp4ff_total_tracks(infile);
|
int numTracks = mp4ff_total_tracks(infile);
|
||||||
@ -60,11 +61,13 @@ static int mp4_getAACTrack(mp4ff_t *infile) {
|
|||||||
rc = AudioSpecificConfig(buff, *buff_size, &mp4ASC);
|
rc = AudioSpecificConfig(buff, *buff_size, &mp4ASC);
|
||||||
#else
|
#else
|
||||||
rc = AudioSpecificConfig(buff, &dummy1_32, &dummy2_8,
|
rc = AudioSpecificConfig(buff, &dummy1_32, &dummy2_8,
|
||||||
&dummy3_8, &dummy4_8, &dummy5_8,
|
&dummy3_8, &dummy4_8,
|
||||||
&dummy6_8, &dummy7_8, &dummy8_8);
|
&dummy5_8, &dummy6_8,
|
||||||
|
&dummy7_8, &dummy8_8);
|
||||||
#endif
|
#endif
|
||||||
free(buff);
|
free(buff);
|
||||||
if (rc < 0) continue;
|
if (rc < 0)
|
||||||
|
continue;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,14 +79,16 @@ static int mp4_getAACTrack(mp4ff_t *infile) {
|
|||||||
static uint32_t mp4_inputStreamReadCallback(void *inStream, void *buffer,
|
static uint32_t mp4_inputStreamReadCallback(void *inStream, void *buffer,
|
||||||
uint32_t length)
|
uint32_t length)
|
||||||
{
|
{
|
||||||
return readFromInputStream((InputStream*) inStream, buffer, 1, length);
|
return readFromInputStream((InputStream *) inStream, buffer, 1, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t mp4_inputStreamSeekCallback(void *inStream, uint64_t position) {
|
static uint32_t mp4_inputStreamSeekCallback(void *inStream, uint64_t position)
|
||||||
|
{
|
||||||
return seekInputStream((InputStream *) inStream, position, SEEK_SET);
|
return seekInputStream((InputStream *) inStream, position, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
static faacDecHandle * openConfigureFaad() {
|
static faacDecHandle *openConfigureFaad()
|
||||||
|
{
|
||||||
faacDecConfigurationPtr config;
|
faacDecConfigurationPtr config;
|
||||||
faacDecHandle decoder = faacDecOpen();
|
faacDecHandle decoder = faacDecOpen();
|
||||||
|
|
||||||
@ -95,20 +100,21 @@ static faacDecHandle * openConfigureFaad() {
|
|||||||
#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
|
#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
|
||||||
config->dontUpSampleImplicitSBR = 0;
|
config->dontUpSampleImplicitSBR = 0;
|
||||||
#endif
|
#endif
|
||||||
faacDecSetConfiguration(decoder,config);
|
faacDecSetConfiguration(decoder, config);
|
||||||
|
|
||||||
return decoder;
|
return decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
|
||||||
mp4ff_t * mp4fh;
|
{
|
||||||
mp4ff_callback_t * mp4cb;
|
mp4ff_t *mp4fh;
|
||||||
|
mp4ff_callback_t *mp4cb;
|
||||||
int32_t track;
|
int32_t track;
|
||||||
float time;
|
float time;
|
||||||
int32_t scale;
|
int32_t scale;
|
||||||
faacDecHandle * decoder;
|
faacDecHandle *decoder;
|
||||||
faacDecFrameInfo frameInfo;
|
faacDecFrameInfo frameInfo;
|
||||||
unsigned char * mp4Buffer;
|
unsigned char *mp4Buffer;
|
||||||
unsigned int mp4BufferSize;
|
unsigned int mp4BufferSize;
|
||||||
uint32_t sampleRate;
|
uint32_t sampleRate;
|
||||||
unsigned char channels;
|
unsigned char channels;
|
||||||
@ -117,10 +123,10 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
int eof = 0;
|
int eof = 0;
|
||||||
long dur;
|
long dur;
|
||||||
unsigned int sampleCount;
|
unsigned int sampleCount;
|
||||||
char * sampleBuffer;
|
char *sampleBuffer;
|
||||||
size_t sampleBufferLen;
|
size_t sampleBufferLen;
|
||||||
unsigned int initial = 1;
|
unsigned int initial = 1;
|
||||||
float * seekTable;
|
float *seekTable;
|
||||||
long seekTableEnd = -1;
|
long seekTableEnd = -1;
|
||||||
int seekPositionFound = 0;
|
int seekPositionFound = 0;
|
||||||
long offset;
|
long offset;
|
||||||
@ -128,7 +134,7 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
int seeking = 0;
|
int seeking = 0;
|
||||||
|
|
||||||
if(openInputStream(&inStream, path) < 0) {
|
if (openInputStream(&inStream, path) < 0) {
|
||||||
ERROR("failed to open %s\n", path);
|
ERROR("failed to open %s\n", path);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -139,7 +145,7 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
mp4cb->user_data = &inStream;
|
mp4cb->user_data = &inStream;
|
||||||
|
|
||||||
mp4fh = mp4ff_open_read(mp4cb);
|
mp4fh = mp4ff_open_read(mp4cb);
|
||||||
if(!mp4fh) {
|
if (!mp4fh) {
|
||||||
ERROR("Input does not appear to be a mp4 stream.\n");
|
ERROR("Input does not appear to be a mp4 stream.\n");
|
||||||
free(mp4cb);
|
free(mp4cb);
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
@ -147,7 +153,7 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
track = mp4_getAACTrack(mp4fh);
|
track = mp4_getAACTrack(mp4fh);
|
||||||
if(track < 0) {
|
if (track < 0) {
|
||||||
ERROR("No AAC track found in mp4 stream.\n");
|
ERROR("No AAC track found in mp4 stream.\n");
|
||||||
mp4ff_close(mp4fh);
|
mp4ff_close(mp4fh);
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
@ -161,11 +167,11 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
|
|
||||||
mp4Buffer = NULL;
|
mp4Buffer = NULL;
|
||||||
mp4BufferSize = 0;
|
mp4BufferSize = 0;
|
||||||
mp4ff_get_decoder_config(mp4fh,track,&mp4Buffer,&mp4BufferSize);
|
mp4ff_get_decoder_config(mp4fh, track, &mp4Buffer, &mp4BufferSize);
|
||||||
|
|
||||||
if(faacDecInit2(decoder,mp4Buffer,mp4BufferSize,&sampleRate,&channels)
|
if (faacDecInit2
|
||||||
< 0)
|
(decoder, mp4Buffer, mp4BufferSize, &sampleRate, &channels)
|
||||||
{
|
< 0) {
|
||||||
ERROR("Error not a AAC stream.\n");
|
ERROR("Error not a AAC stream.\n");
|
||||||
faacDecClose(decoder);
|
faacDecClose(decoder);
|
||||||
mp4ff_close(mp4fh);
|
mp4ff_close(mp4fh);
|
||||||
@ -176,12 +182,13 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
|
|
||||||
dc->audioFormat.sampleRate = sampleRate;
|
dc->audioFormat.sampleRate = sampleRate;
|
||||||
dc->audioFormat.channels = channels;
|
dc->audioFormat.channels = channels;
|
||||||
time = mp4ff_get_track_duration_use_offsets(mp4fh,track);
|
time = mp4ff_get_track_duration_use_offsets(mp4fh, track);
|
||||||
scale = mp4ff_time_scale(mp4fh,track);
|
scale = mp4ff_time_scale(mp4fh, track);
|
||||||
|
|
||||||
if(mp4Buffer) free(mp4Buffer);
|
if (mp4Buffer)
|
||||||
|
free(mp4Buffer);
|
||||||
|
|
||||||
if(scale < 0) {
|
if (scale < 0) {
|
||||||
ERROR("Error getting audio format of mp4 AAC track.\n");
|
ERROR("Error getting audio format of mp4 AAC track.\n");
|
||||||
faacDecClose(decoder);
|
faacDecClose(decoder);
|
||||||
mp4ff_close(mp4fh);
|
mp4ff_close(mp4fh);
|
||||||
@ -189,66 +196,71 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
free(mp4cb);
|
free(mp4cb);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
dc->totalTime = ((float)time)/scale;
|
dc->totalTime = ((float)time) / scale;
|
||||||
|
|
||||||
numSamples = mp4ff_num_samples(mp4fh,track);
|
numSamples = mp4ff_num_samples(mp4fh, track);
|
||||||
|
|
||||||
time = 0.0;
|
time = 0.0;
|
||||||
|
|
||||||
seekTable = malloc(sizeof(float)*numSamples);
|
seekTable = malloc(sizeof(float) * numSamples);
|
||||||
|
|
||||||
for(sampleId=0; sampleId<numSamples && !eof; sampleId++) {
|
for (sampleId = 0; sampleId < numSamples && !eof; sampleId++) {
|
||||||
if(dc->seek) seeking = 1;
|
if (dc->seek)
|
||||||
|
seeking = 1;
|
||||||
|
|
||||||
if(seeking && seekTableEnd>1 &&
|
if (seeking && seekTableEnd > 1 &&
|
||||||
seekTable[seekTableEnd]>=dc->seekWhere)
|
seekTable[seekTableEnd] >= dc->seekWhere) {
|
||||||
{
|
|
||||||
int i = 2;
|
int i = 2;
|
||||||
while(seekTable[i]<dc->seekWhere) i++;
|
while (seekTable[i] < dc->seekWhere)
|
||||||
sampleId = i-1;
|
i++;
|
||||||
|
sampleId = i - 1;
|
||||||
time = seekTable[sampleId];
|
time = seekTable[sampleId];
|
||||||
}
|
}
|
||||||
|
|
||||||
dur = mp4ff_get_sample_duration(mp4fh,track,sampleId);
|
dur = mp4ff_get_sample_duration(mp4fh, track, sampleId);
|
||||||
offset = mp4ff_get_sample_offset(mp4fh,track,sampleId);
|
offset = mp4ff_get_sample_offset(mp4fh, track, sampleId);
|
||||||
|
|
||||||
if(sampleId>seekTableEnd) {
|
if (sampleId > seekTableEnd) {
|
||||||
seekTable[sampleId] = time;
|
seekTable[sampleId] = time;
|
||||||
seekTableEnd = sampleId;
|
seekTableEnd = sampleId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sampleId==0) dur = 0;
|
if (sampleId == 0)
|
||||||
if(offset>dur) dur = 0;
|
dur = 0;
|
||||||
else dur-=offset;
|
if (offset > dur)
|
||||||
time+=((float)dur)/scale;
|
dur = 0;
|
||||||
|
else
|
||||||
|
dur -= offset;
|
||||||
|
time += ((float)dur) / scale;
|
||||||
|
|
||||||
if(seeking && time>dc->seekWhere) seekPositionFound = 1;
|
if (seeking && time > dc->seekWhere)
|
||||||
|
seekPositionFound = 1;
|
||||||
|
|
||||||
if(seeking && seekPositionFound) {
|
if (seeking && seekPositionFound) {
|
||||||
seekPositionFound = 0;
|
seekPositionFound = 0;
|
||||||
clearOutputBuffer(cb);
|
clearOutputBuffer(cb);
|
||||||
seeking = 0;
|
seeking = 0;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(seeking) continue;
|
if (seeking)
|
||||||
|
continue;
|
||||||
|
|
||||||
if(mp4ff_read_sample(mp4fh,track,sampleId,&mp4Buffer,
|
if (mp4ff_read_sample(mp4fh, track, sampleId, &mp4Buffer,
|
||||||
&mp4BufferSize) == 0)
|
&mp4BufferSize) == 0) {
|
||||||
{
|
|
||||||
eof = 1;
|
eof = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_FAAD_BUFLEN_FUNCS
|
#ifdef HAVE_FAAD_BUFLEN_FUNCS
|
||||||
sampleBuffer = faacDecDecode(decoder,&frameInfo,mp4Buffer,
|
sampleBuffer = faacDecDecode(decoder, &frameInfo, mp4Buffer,
|
||||||
mp4BufferSize);
|
mp4BufferSize);
|
||||||
#else
|
#else
|
||||||
sampleBuffer = faacDecDecode(decoder,&frameInfo,mp4Buffer);
|
sampleBuffer = faacDecDecode(decoder, &frameInfo, mp4Buffer);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(mp4Buffer) free(mp4Buffer);
|
if (mp4Buffer)
|
||||||
if(frameInfo.error > 0) {
|
free(mp4Buffer);
|
||||||
|
if (frameInfo.error > 0) {
|
||||||
ERROR("error decoding MP4 file: %s\n", path);
|
ERROR("error decoding MP4 file: %s\n", path);
|
||||||
ERROR("faad2 error: %s\n",
|
ERROR("faad2 error: %s\n",
|
||||||
faacDecGetErrorMessage(frameInfo.error));
|
faacDecGetErrorMessage(frameInfo.error));
|
||||||
@ -256,7 +268,7 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(dc->state != DECODE_STATE_DECODE) {
|
if (dc->state != DECODE_STATE_DECODE) {
|
||||||
channels = frameInfo.channels;
|
channels = frameInfo.channels;
|
||||||
#ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE
|
#ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE
|
||||||
scale = frameInfo.samplerate;
|
scale = frameInfo.samplerate;
|
||||||
@ -268,28 +280,27 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(channels*(dur+offset) > frameInfo.samples) {
|
if (channels * (dur + offset) > frameInfo.samples) {
|
||||||
dur = frameInfo.samples/channels;
|
dur = frameInfo.samples / channels;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sampleCount = (unsigned long)(dur*channels);
|
sampleCount = (unsigned long)(dur * channels);
|
||||||
|
|
||||||
if(sampleCount>0) {
|
if (sampleCount > 0) {
|
||||||
initial =0;
|
initial = 0;
|
||||||
bitRate = frameInfo.bytesconsumed*8.0*
|
bitRate = frameInfo.bytesconsumed * 8.0 *
|
||||||
frameInfo.channels*scale/
|
frameInfo.channels * scale /
|
||||||
frameInfo.samples/1000+0.5;
|
frameInfo.samples / 1000 + 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sampleBufferLen = sampleCount * 2;
|
||||||
|
|
||||||
sampleBufferLen = sampleCount*2;
|
sampleBuffer += offset * channels * 2;
|
||||||
|
|
||||||
sampleBuffer+=offset*channels*2;
|
|
||||||
|
|
||||||
sendDataToOutputBuffer(cb, NULL, dc, 1, sampleBuffer,
|
sendDataToOutputBuffer(cb, NULL, dc, 1, sampleBuffer,
|
||||||
sampleBufferLen, time, bitRate, NULL);
|
sampleBufferLen, time, bitRate, NULL);
|
||||||
if(dc->stop) {
|
if (dc->stop) {
|
||||||
eof = 1;
|
eof = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -301,25 +312,28 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
|
|||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
free(mp4cb);
|
free(mp4cb);
|
||||||
|
|
||||||
if(dc->state != DECODE_STATE_DECODE) return -1;
|
if (dc->state != DECODE_STATE_DECODE)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(dc->seek && seeking) {
|
if (dc->seek && seeking) {
|
||||||
clearOutputBuffer(cb);
|
clearOutputBuffer(cb);
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
flushOutputBuffer(cb);
|
flushOutputBuffer(cb);
|
||||||
|
|
||||||
if(dc->stop) dc->stop = 0;
|
if (dc->stop)
|
||||||
|
dc->stop = 0;
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * mp4DataDup(char * file, int * mp4MetadataFound) {
|
static MpdTag *mp4DataDup(char *file, int *mp4MetadataFound)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
|
MpdTag *ret = NULL;
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
mp4ff_t * mp4fh;
|
mp4ff_t *mp4fh;
|
||||||
mp4ff_callback_t * cb;
|
mp4ff_callback_t *cb;
|
||||||
int32_t track;
|
int32_t track;
|
||||||
int32_t time;
|
int32_t time;
|
||||||
int32_t scale;
|
int32_t scale;
|
||||||
@ -327,7 +341,7 @@ static MpdTag * mp4DataDup(char * file, int * mp4MetadataFound) {
|
|||||||
|
|
||||||
*mp4MetadataFound = 0;
|
*mp4MetadataFound = 0;
|
||||||
|
|
||||||
if(openInputStream(&inStream, file) < 0) {
|
if (openInputStream(&inStream, file) < 0) {
|
||||||
DEBUG("mp4DataDup: Failed to open file: %s\n", file);
|
DEBUG("mp4DataDup: Failed to open file: %s\n", file);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -338,14 +352,14 @@ static MpdTag * mp4DataDup(char * file, int * mp4MetadataFound) {
|
|||||||
cb->user_data = &inStream;
|
cb->user_data = &inStream;
|
||||||
|
|
||||||
mp4fh = mp4ff_open_read(cb);
|
mp4fh = mp4ff_open_read(cb);
|
||||||
if(!mp4fh) {
|
if (!mp4fh) {
|
||||||
free(cb);
|
free(cb);
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
track = mp4_getAACTrack(mp4fh);
|
track = mp4_getAACTrack(mp4fh);
|
||||||
if(track < 0) {
|
if (track < 0) {
|
||||||
mp4ff_close(mp4fh);
|
mp4ff_close(mp4fh);
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
free(cb);
|
free(cb);
|
||||||
@ -353,48 +367,42 @@ static MpdTag * mp4DataDup(char * file, int * mp4MetadataFound) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = newMpdTag();
|
ret = newMpdTag();
|
||||||
time = mp4ff_get_track_duration_use_offsets(mp4fh,track);
|
time = mp4ff_get_track_duration_use_offsets(mp4fh, track);
|
||||||
scale = mp4ff_time_scale(mp4fh,track);
|
scale = mp4ff_time_scale(mp4fh, track);
|
||||||
if(scale < 0) {
|
if (scale < 0) {
|
||||||
mp4ff_close(mp4fh);
|
mp4ff_close(mp4fh);
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
free(cb);
|
free(cb);
|
||||||
freeMpdTag(ret);
|
freeMpdTag(ret);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ret->time = ((float)time)/scale+0.5;
|
ret->time = ((float)time) / scale + 0.5;
|
||||||
|
|
||||||
for(i = 0; i < mp4ff_meta_get_num_items(mp4fh); i++) {
|
for (i = 0; i < mp4ff_meta_get_num_items(mp4fh); i++) {
|
||||||
char * item;
|
char *item;
|
||||||
char * value;
|
char *value;
|
||||||
|
|
||||||
mp4ff_meta_get_by_index(mp4fh, i, &item, &value);
|
mp4ff_meta_get_by_index(mp4fh, i, &item, &value);
|
||||||
|
|
||||||
if(0 == strcasecmp("artist", item)) {
|
if (0 == strcasecmp("artist", item)) {
|
||||||
addItemToMpdTag(ret, TAG_ITEM_ARTIST, value);
|
addItemToMpdTag(ret, TAG_ITEM_ARTIST, value);
|
||||||
*mp4MetadataFound = 1;
|
*mp4MetadataFound = 1;
|
||||||
}
|
} else if (0 == strcasecmp("title", item)) {
|
||||||
else if(0 == strcasecmp("title", item)) {
|
|
||||||
addItemToMpdTag(ret, TAG_ITEM_TITLE, value);
|
addItemToMpdTag(ret, TAG_ITEM_TITLE, value);
|
||||||
*mp4MetadataFound = 1;
|
*mp4MetadataFound = 1;
|
||||||
}
|
} else if (0 == strcasecmp("album", item)) {
|
||||||
else if(0 == strcasecmp("album", item)) {
|
|
||||||
addItemToMpdTag(ret, TAG_ITEM_ALBUM, value);
|
addItemToMpdTag(ret, TAG_ITEM_ALBUM, value);
|
||||||
*mp4MetadataFound = 1;
|
*mp4MetadataFound = 1;
|
||||||
}
|
} else if (0 == strcasecmp("track", item)) {
|
||||||
else if(0 == strcasecmp("track", item)) {
|
|
||||||
addItemToMpdTag(ret, TAG_ITEM_TRACK, value);
|
addItemToMpdTag(ret, TAG_ITEM_TRACK, value);
|
||||||
*mp4MetadataFound = 1;
|
*mp4MetadataFound = 1;
|
||||||
}
|
} else if (0 == strcasecmp("disc", item)) { /* Is that the correct id? */
|
||||||
else if(0 == strcasecmp("disc", item)) { /* Is that the correct id? */
|
|
||||||
addItemToMpdTag(ret, TAG_ITEM_DISC, value);
|
addItemToMpdTag(ret, TAG_ITEM_DISC, value);
|
||||||
*mp4MetadataFound = 1;
|
*mp4MetadataFound = 1;
|
||||||
}
|
} else if (0 == strcasecmp("genre", item)) {
|
||||||
else if(0 == strcasecmp("genre", item)) {
|
|
||||||
addItemToMpdTag(ret, TAG_ITEM_GENRE, value);
|
addItemToMpdTag(ret, TAG_ITEM_GENRE, value);
|
||||||
*mp4MetadataFound = 1;
|
*mp4MetadataFound = 1;
|
||||||
}
|
} else if (0 == strcasecmp("date", item)) {
|
||||||
else if(0 == strcasecmp("date", item)) {
|
|
||||||
addItemToMpdTag(ret, TAG_ITEM_DATE, value);
|
addItemToMpdTag(ret, TAG_ITEM_DATE, value);
|
||||||
*mp4MetadataFound = 1;
|
*mp4MetadataFound = 1;
|
||||||
}
|
}
|
||||||
@ -410,15 +418,17 @@ static MpdTag * mp4DataDup(char * file, int * mp4MetadataFound) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * mp4TagDup(char * file) {
|
static MpdTag *mp4TagDup(char *file)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
|
MpdTag *ret = NULL;
|
||||||
int mp4MetadataFound = 0;
|
int mp4MetadataFound = 0;
|
||||||
|
|
||||||
ret = mp4DataDup(file, &mp4MetadataFound);
|
ret = mp4DataDup(file, &mp4MetadataFound);
|
||||||
if(!ret) return NULL;
|
if (!ret)
|
||||||
if(!mp4MetadataFound) {
|
return NULL;
|
||||||
MpdTag * temp = id3Dup(file);
|
if (!mp4MetadataFound) {
|
||||||
if(temp) {
|
MpdTag *temp = id3Dup(file);
|
||||||
|
if (temp) {
|
||||||
temp->time = ret->time;
|
temp->time = ret->time;
|
||||||
freeMpdTag(ret);
|
freeMpdTag(ret);
|
||||||
ret = temp;
|
ret = temp;
|
||||||
@ -428,10 +438,9 @@ static MpdTag * mp4TagDup(char * file) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * mp4Suffixes[] = {"m4a", "mp4", NULL};
|
static char *mp4Suffixes[] = { "m4a", "mp4", NULL };
|
||||||
|
|
||||||
InputPlugin mp4Plugin =
|
InputPlugin mp4Plugin = {
|
||||||
{
|
|
||||||
"mp4",
|
"mp4",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -446,8 +455,7 @@ InputPlugin mp4Plugin =
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
InputPlugin mp4Plugin =
|
InputPlugin mp4Plugin = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -37,53 +37,58 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
typedef struct _MpcCallbackData {
|
typedef struct _MpcCallbackData {
|
||||||
InputStream * inStream;
|
InputStream *inStream;
|
||||||
DecoderControl * dc;
|
DecoderControl *dc;
|
||||||
} MpcCallbackData;
|
} MpcCallbackData;
|
||||||
|
|
||||||
static mpc_int32_t mpc_read_cb(void * vdata, void * ptr, mpc_int32_t size) {
|
static mpc_int32_t mpc_read_cb(void *vdata, void *ptr, mpc_int32_t size)
|
||||||
|
{
|
||||||
mpc_int32_t ret = 0;
|
mpc_int32_t ret = 0;
|
||||||
MpcCallbackData * data = (MpcCallbackData *)vdata;
|
MpcCallbackData *data = (MpcCallbackData *) vdata;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
ret = readFromInputStream(data->inStream, ptr, 1, size);
|
ret = readFromInputStream(data->inStream, ptr, 1, size);
|
||||||
if(ret == 0 && !inputStreamAtEOF(data->inStream) &&
|
if (ret == 0 && !inputStreamAtEOF(data->inStream) &&
|
||||||
(data->dc && !data->dc->stop))
|
(data->dc && !data->dc->stop)) {
|
||||||
{
|
|
||||||
my_usleep(10000);
|
my_usleep(10000);
|
||||||
}
|
} else
|
||||||
else break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mpc_bool_t mpc_seek_cb(void * vdata, mpc_int32_t offset) {
|
static mpc_bool_t mpc_seek_cb(void *vdata, mpc_int32_t offset)
|
||||||
MpcCallbackData * data = (MpcCallbackData *)vdata;
|
{
|
||||||
|
MpcCallbackData *data = (MpcCallbackData *) vdata;
|
||||||
|
|
||||||
return seekInputStream(data->inStream , offset, SEEK_SET) < 0 ? 0 : 1;
|
return seekInputStream(data->inStream, offset, SEEK_SET) < 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mpc_int32_t mpc_tell_cb(void * vdata) {
|
static mpc_int32_t mpc_tell_cb(void *vdata)
|
||||||
MpcCallbackData * data = (MpcCallbackData *)vdata;
|
{
|
||||||
|
MpcCallbackData *data = (MpcCallbackData *) vdata;
|
||||||
|
|
||||||
return (long)(data->inStream->offset);
|
return (long)(data->inStream->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static mpc_bool_t mpc_canseek_cb(void * vdata) {
|
static mpc_bool_t mpc_canseek_cb(void *vdata)
|
||||||
MpcCallbackData * data = (MpcCallbackData *)vdata;
|
{
|
||||||
|
MpcCallbackData *data = (MpcCallbackData *) vdata;
|
||||||
|
|
||||||
return data->inStream->seekable;
|
return data->inStream->seekable;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mpc_int32_t mpc_getsize_cb(void * vdata) {
|
static mpc_int32_t mpc_getsize_cb(void *vdata)
|
||||||
MpcCallbackData * data = (MpcCallbackData *)vdata;
|
{
|
||||||
|
MpcCallbackData *data = (MpcCallbackData *) vdata;
|
||||||
|
|
||||||
return data->inStream->size;
|
return data->inStream->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this _looks_ performance-critical, don't de-inline -- eric */
|
/* this _looks_ performance-critical, don't de-inline -- eric */
|
||||||
static inline mpd_sint16 convertSample(MPC_SAMPLE_FORMAT sample) {
|
static inline mpd_sint16 convertSample(MPC_SAMPLE_FORMAT sample)
|
||||||
|
{
|
||||||
/* only doing 16-bit audio for now */
|
/* only doing 16-bit audio for now */
|
||||||
mpd_sint32 val;
|
mpd_sint32 val;
|
||||||
|
|
||||||
@ -93,10 +98,9 @@ static inline mpd_sint16 convertSample(MPC_SAMPLE_FORMAT sample) {
|
|||||||
#ifdef MPC_FIXED_POINT
|
#ifdef MPC_FIXED_POINT
|
||||||
const int shift = 16 - MPC_FIXED_POINT_SCALE_SHIFT;
|
const int shift = 16 - MPC_FIXED_POINT_SCALE_SHIFT;
|
||||||
|
|
||||||
if( ssample > 0 ) {
|
if (ssample > 0) {
|
||||||
sample <<= shift;
|
sample <<= shift;
|
||||||
}
|
} else if (shift < 0) {
|
||||||
else if ( shift < 0 ) {
|
|
||||||
sample >>= -shift;
|
sample >>= -shift;
|
||||||
}
|
}
|
||||||
val = sample;
|
val = sample;
|
||||||
@ -106,8 +110,10 @@ static inline mpd_sint16 convertSample(MPC_SAMPLE_FORMAT sample) {
|
|||||||
val = sample * float_scale;
|
val = sample * float_scale;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( val < clip_min) val = clip_min;
|
if (val < clip_min)
|
||||||
else if ( val > clip_max ) val = clip_max;
|
val = clip_min;
|
||||||
|
else if (val > clip_max)
|
||||||
|
val = clip_max;
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -129,13 +135,13 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
char chunk[MPC_CHUNK_SIZE];
|
char chunk[MPC_CHUNK_SIZE];
|
||||||
int chunkpos = 0;
|
int chunkpos = 0;
|
||||||
long bitRate = 0;
|
long bitRate = 0;
|
||||||
mpd_sint16 * s16 = (mpd_sint16 *) chunk;
|
mpd_sint16 *s16 = (mpd_sint16 *) chunk;
|
||||||
unsigned long samplePos = 0;
|
unsigned long samplePos = 0;
|
||||||
mpc_uint32_t vbrUpdateAcc;
|
mpc_uint32_t vbrUpdateAcc;
|
||||||
mpc_uint32_t vbrUpdateBits;
|
mpc_uint32_t vbrUpdateBits;
|
||||||
float time;
|
float time;
|
||||||
int i;
|
int i;
|
||||||
ReplayGainInfo * replayGainInfo = NULL;
|
ReplayGainInfo *replayGainInfo = NULL;
|
||||||
|
|
||||||
data.inStream = inStream;
|
data.inStream = inStream;
|
||||||
data.dc = dc;
|
data.dc = dc;
|
||||||
@ -149,13 +155,12 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
|
|
||||||
mpc_streaminfo_init(&info);
|
mpc_streaminfo_init(&info);
|
||||||
|
|
||||||
if((ret = mpc_streaminfo_read(&info, &reader)) != ERROR_CODE_OK) {
|
if ((ret = mpc_streaminfo_read(&info, &reader)) != ERROR_CODE_OK) {
|
||||||
closeInputStream(inStream);
|
closeInputStream(inStream);
|
||||||
if(!dc->stop) {
|
if (!dc->stop) {
|
||||||
ERROR("Not a valid musepack stream");
|
ERROR("Not a valid musepack stream");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
}
|
}
|
||||||
@ -164,12 +169,11 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
|
|
||||||
mpc_decoder_setup(&decoder, &reader);
|
mpc_decoder_setup(&decoder, &reader);
|
||||||
|
|
||||||
if(!mpc_decoder_initialize(&decoder, &info)) {
|
if (!mpc_decoder_initialize(&decoder, &info)) {
|
||||||
closeInputStream(inStream);
|
closeInputStream(inStream);
|
||||||
if(!dc->stop) {
|
if (!dc->stop) {
|
||||||
ERROR("Not a valid musepack stream");
|
ERROR("Not a valid musepack stream");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
}
|
}
|
||||||
@ -191,14 +195,14 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
|
|
||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
|
|
||||||
while(!eof) {
|
while (!eof) {
|
||||||
if(dc->seek) {
|
if (dc->seek) {
|
||||||
samplePos = dc->seekWhere * dc->audioFormat.sampleRate;
|
samplePos = dc->seekWhere * dc->audioFormat.sampleRate;
|
||||||
if(mpc_decoder_seek_sample(&decoder, samplePos)) {
|
if (mpc_decoder_seek_sample(&decoder, samplePos)) {
|
||||||
clearOutputBuffer(cb);
|
clearOutputBuffer(cb);
|
||||||
chunkpos = 0;
|
chunkpos = 0;
|
||||||
}
|
} else
|
||||||
else dc->seekError = 1;
|
dc->seekError = 1;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +211,7 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
ret = mpc_decoder_decode(&decoder, sample_buffer,
|
ret = mpc_decoder_decode(&decoder, sample_buffer,
|
||||||
&vbrUpdateAcc, &vbrUpdateBits);
|
&vbrUpdateAcc, &vbrUpdateBits);
|
||||||
|
|
||||||
if(ret <= 0 || dc->stop ) {
|
if (ret <= 0 || dc->stop) {
|
||||||
eof = 1;
|
eof = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -217,30 +221,28 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
/* ret is in samples, and we have stereo */
|
/* ret is in samples, and we have stereo */
|
||||||
ret *= 2;
|
ret *= 2;
|
||||||
|
|
||||||
for(i = 0; i < ret; i++) {
|
for (i = 0; i < ret; i++) {
|
||||||
/* 16 bit audio again */
|
/* 16 bit audio again */
|
||||||
*s16 = convertSample(sample_buffer[i]);
|
*s16 = convertSample(sample_buffer[i]);
|
||||||
chunkpos += 2;
|
chunkpos += 2;
|
||||||
s16++;
|
s16++;
|
||||||
|
|
||||||
if(chunkpos >= MPC_CHUNK_SIZE) {
|
if (chunkpos >= MPC_CHUNK_SIZE) {
|
||||||
time = ((float)samplePos) /
|
time = ((float)samplePos) /
|
||||||
dc->audioFormat.sampleRate;
|
dc->audioFormat.sampleRate;
|
||||||
|
|
||||||
bitRate = vbrUpdateBits *
|
bitRate = vbrUpdateBits *
|
||||||
dc->audioFormat.sampleRate /
|
dc->audioFormat.sampleRate / 1152 / 1000;
|
||||||
1152 / 1000;
|
|
||||||
|
|
||||||
sendDataToOutputBuffer(cb, inStream, dc,
|
sendDataToOutputBuffer(cb, inStream, dc,
|
||||||
inStream->seekable,
|
inStream->seekable,
|
||||||
chunk, chunkpos,
|
chunk, chunkpos,
|
||||||
time,
|
time,
|
||||||
bitRate,
|
bitRate, replayGainInfo);
|
||||||
replayGainInfo);
|
|
||||||
|
|
||||||
chunkpos = 0;
|
chunkpos = 0;
|
||||||
s16 = (mpd_sint16 *)chunk;
|
s16 = (mpd_sint16 *) chunk;
|
||||||
if(dc->stop) {
|
if (dc->stop) {
|
||||||
eof = 1;
|
eof = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -248,10 +250,11 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!dc->stop && chunkpos > 0) {
|
if (!dc->stop && chunkpos > 0) {
|
||||||
time = ((float)samplePos) / dc->audioFormat.sampleRate;
|
time = ((float)samplePos) / dc->audioFormat.sampleRate;
|
||||||
|
|
||||||
bitRate = vbrUpdateBits * dc->audioFormat.sampleRate / 1152 / 1000;
|
bitRate =
|
||||||
|
vbrUpdateBits * dc->audioFormat.sampleRate / 1152 / 1000;
|
||||||
|
|
||||||
sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
|
sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
|
||||||
chunk, chunkpos, time, bitRate,
|
chunk, chunkpos, time, bitRate,
|
||||||
@ -264,18 +267,18 @@ static int mpc_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
|
|
||||||
freeReplayGainInfo(replayGainInfo);
|
freeReplayGainInfo(replayGainInfo);
|
||||||
|
|
||||||
if(dc->stop) {
|
if (dc->stop) {
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float mpcGetTime(char * file) {
|
static float mpcGetTime(char *file)
|
||||||
|
{
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
float time = -1;
|
float time = -1;
|
||||||
|
|
||||||
@ -295,12 +298,12 @@ static float mpcGetTime(char * file) {
|
|||||||
|
|
||||||
mpc_streaminfo_init(&info);
|
mpc_streaminfo_init(&info);
|
||||||
|
|
||||||
if(openInputStream(&inStream, file) < 0) {
|
if (openInputStream(&inStream, file) < 0) {
|
||||||
DEBUG("mpcGetTime: Failed to open file: %s\n", file);
|
DEBUG("mpcGetTime: Failed to open file: %s\n", file);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
|
if (mpc_streaminfo_read(&info, &reader) != ERROR_CODE_OK) {
|
||||||
closeInputStream(&inStream);
|
closeInputStream(&inStream);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -312,28 +315,31 @@ static float mpcGetTime(char * file) {
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * mpcTagDup(char * file) {
|
static MpdTag *mpcTagDup(char *file)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
|
MpdTag *ret = NULL;
|
||||||
float time = mpcGetTime(file);
|
float time = mpcGetTime(file);
|
||||||
|
|
||||||
if(time < 0) {
|
if (time < 0) {
|
||||||
DEBUG("mpcTagDup: Failed to get Songlength of file: %s\n",file);
|
DEBUG("mpcTagDup: Failed to get Songlength of file: %s\n",
|
||||||
|
file);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = apeDup(file);
|
ret = apeDup(file);
|
||||||
if(!ret) ret = id3Dup(file);
|
if (!ret)
|
||||||
if(!ret) ret = newMpdTag();
|
ret = id3Dup(file);
|
||||||
|
if (!ret)
|
||||||
|
ret = newMpdTag();
|
||||||
ret->time = time;
|
ret->time = time;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * mpcSuffixes[] = {"mpc", NULL};
|
static char *mpcSuffixes[] = { "mpc", NULL };
|
||||||
static char * mpcMimeTypes[] = {NULL};
|
static char *mpcMimeTypes[] = { NULL };
|
||||||
|
|
||||||
InputPlugin mpcPlugin =
|
InputPlugin mpcPlugin = {
|
||||||
{
|
|
||||||
"mpc",
|
"mpc",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -348,8 +354,7 @@ InputPlugin mpcPlugin =
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
InputPlugin mpcPlugin =
|
InputPlugin mpcPlugin = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -51,14 +51,18 @@ static void oggflac_cleanup(InputStream * inStream,
|
|||||||
closeInputStream(inStream);
|
closeInputStream(inStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static OggFLAC__SeekableStreamDecoderReadStatus of_read_cb(
|
static OggFLAC__SeekableStreamDecoderReadStatus of_read_cb(const
|
||||||
const OggFLAC__SeekableStreamDecoder * decoder,
|
OggFLAC__SeekableStreamDecoder
|
||||||
FLAC__byte buf[], unsigned * bytes, void * fdata) {
|
* decoder,
|
||||||
FlacData * data = (FlacData *) fdata;
|
FLAC__byte buf[],
|
||||||
|
unsigned *bytes,
|
||||||
|
void *fdata)
|
||||||
|
{
|
||||||
|
FlacData *data = (FlacData *) fdata;
|
||||||
size_t r;
|
size_t r;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
r = readFromInputStream(data->inStream,(void *)buf,1,*bytes);
|
r = readFromInputStream(data->inStream, (void *)buf, 1, *bytes);
|
||||||
if (r == 0 && !inputStreamAtEOF(data->inStream) &&
|
if (r == 0 && !inputStreamAtEOF(data->inStream) &&
|
||||||
!data->dc->stop)
|
!data->dc->stop)
|
||||||
my_usleep(10000);
|
my_usleep(10000);
|
||||||
@ -73,44 +77,52 @@ static OggFLAC__SeekableStreamDecoderReadStatus of_read_cb(
|
|||||||
return OggFLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
|
return OggFLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OggFLAC__SeekableStreamDecoderSeekStatus of_seek_cb(
|
static OggFLAC__SeekableStreamDecoderSeekStatus of_seek_cb(const
|
||||||
const OggFLAC__SeekableStreamDecoder * decoder,
|
OggFLAC__SeekableStreamDecoder
|
||||||
FLAC__uint64 offset, void * fdata)
|
* decoder,
|
||||||
|
FLAC__uint64 offset,
|
||||||
|
void *fdata)
|
||||||
{
|
{
|
||||||
FlacData * data = (FlacData *) fdata;
|
FlacData *data = (FlacData *) fdata;
|
||||||
|
|
||||||
if(seekInputStream(data->inStream,offset,SEEK_SET)<0) {
|
if (seekInputStream(data->inStream, offset, SEEK_SET) < 0) {
|
||||||
return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
|
return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
|
return OggFLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OggFLAC__SeekableStreamDecoderTellStatus of_tell_cb(
|
static OggFLAC__SeekableStreamDecoderTellStatus of_tell_cb(const
|
||||||
const OggFLAC__SeekableStreamDecoder * decoder,
|
OggFLAC__SeekableStreamDecoder
|
||||||
FLAC__uint64 * offset, void * fdata)
|
* decoder,
|
||||||
|
FLAC__uint64 *
|
||||||
|
offset, void *fdata)
|
||||||
{
|
{
|
||||||
FlacData * data = (FlacData *) fdata;
|
FlacData *data = (FlacData *) fdata;
|
||||||
|
|
||||||
*offset = (long)(data->inStream->offset);
|
*offset = (long)(data->inStream->offset);
|
||||||
|
|
||||||
return OggFLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
|
return OggFLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OggFLAC__SeekableStreamDecoderLengthStatus of_length_cb(
|
static OggFLAC__SeekableStreamDecoderLengthStatus of_length_cb(const
|
||||||
const OggFLAC__SeekableStreamDecoder * decoder,
|
OggFLAC__SeekableStreamDecoder
|
||||||
FLAC__uint64 * length, void * fdata)
|
* decoder,
|
||||||
|
FLAC__uint64 *
|
||||||
|
length,
|
||||||
|
void *fdata)
|
||||||
{
|
{
|
||||||
FlacData * data = (FlacData *) fdata;
|
FlacData *data = (FlacData *) fdata;
|
||||||
|
|
||||||
*length = (size_t)(data->inStream->size);
|
*length = (size_t) (data->inStream->size);
|
||||||
|
|
||||||
return OggFLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
|
return OggFLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__bool of_EOF_cb(const OggFLAC__SeekableStreamDecoder * decoder,
|
static FLAC__bool of_EOF_cb(const OggFLAC__SeekableStreamDecoder * decoder,
|
||||||
void * fdata) {
|
void *fdata)
|
||||||
FlacData * data = (FlacData *) fdata;
|
{
|
||||||
|
FlacData *data = (FlacData *) fdata;
|
||||||
|
|
||||||
if (inputStreamAtEOF(data->inStream) == 1)
|
if (inputStreamAtEOF(data->inStream) == 1)
|
||||||
return true;
|
return true;
|
||||||
@ -120,12 +132,12 @@ static FLAC__bool of_EOF_cb(const OggFLAC__SeekableStreamDecoder * decoder,
|
|||||||
static void of_error_cb(const OggFLAC__SeekableStreamDecoder * decoder,
|
static void of_error_cb(const OggFLAC__SeekableStreamDecoder * decoder,
|
||||||
FLAC__StreamDecoderErrorStatus status, void *fdata)
|
FLAC__StreamDecoderErrorStatus status, void *fdata)
|
||||||
{
|
{
|
||||||
flac_error_common_cb("oggflac",status,(FlacData *) fdata);
|
flac_error_common_cb("oggflac", status, (FlacData *) fdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void oggflacPrintErroredState(OggFLAC__SeekableStreamDecoderState state)
|
static void oggflacPrintErroredState(OggFLAC__SeekableStreamDecoderState state)
|
||||||
{
|
{
|
||||||
switch(state) {
|
switch (state) {
|
||||||
case OggFLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
|
case OggFLAC__SEEKABLE_STREAM_DECODER_MEMORY_ALLOCATION_ERROR:
|
||||||
ERROR("oggflac allocation error\n");
|
ERROR("oggflac allocation error\n");
|
||||||
break;
|
break;
|
||||||
@ -154,21 +166,23 @@ static void oggflacPrintErroredState(OggFLAC__SeekableStreamDecoderState state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FLAC__StreamDecoderWriteStatus oggflacWrite(
|
static FLAC__StreamDecoderWriteStatus oggflacWrite(const
|
||||||
const OggFLAC__SeekableStreamDecoder *decoder,
|
OggFLAC__SeekableStreamDecoder
|
||||||
const FLAC__Frame *frame, const FLAC__int32 * const buf[],
|
* decoder,
|
||||||
void * vdata)
|
const FLAC__Frame * frame,
|
||||||
|
const FLAC__int32 *
|
||||||
|
const buf[], void *vdata)
|
||||||
{
|
{
|
||||||
FlacData * data = (FlacData *)vdata;
|
FlacData *data = (FlacData *) vdata;
|
||||||
FLAC__uint32 samples = frame->header.blocksize;
|
FLAC__uint32 samples = frame->header.blocksize;
|
||||||
FLAC__uint16 u16;
|
FLAC__uint16 u16;
|
||||||
unsigned char * uc;
|
unsigned char *uc;
|
||||||
int c_samp, c_chan, d_samp;
|
int c_samp, c_chan, d_samp;
|
||||||
int i;
|
int i;
|
||||||
float timeChange;
|
float timeChange;
|
||||||
|
|
||||||
timeChange = ((float)samples)/frame->header.sample_rate;
|
timeChange = ((float)samples) / frame->header.sample_rate;
|
||||||
data->time+= timeChange;
|
data->time += timeChange;
|
||||||
|
|
||||||
/* ogg123 uses a complicated method of calculating bitrate
|
/* ogg123 uses a complicated method of calculating bitrate
|
||||||
* with averaging which I'm not too fond of.
|
* with averaging which I'm not too fond of.
|
||||||
@ -182,19 +196,21 @@ static FLAC__StreamDecoderWriteStatus oggflacWrite(
|
|||||||
/((float)samples * 1000)) + 0.5;
|
/((float)samples * 1000)) + 0.5;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for(c_samp = d_samp = 0; c_samp < frame->header.blocksize; c_samp++) {
|
for (c_samp = d_samp = 0; c_samp < frame->header.blocksize; c_samp++) {
|
||||||
for(c_chan = 0; c_chan < frame->header.channels;
|
for (c_chan = 0; c_chan < frame->header.channels;
|
||||||
c_chan++, d_samp++) {
|
c_chan++, d_samp++) {
|
||||||
u16 = buf[c_chan][c_samp];
|
u16 = buf[c_chan][c_samp];
|
||||||
uc = (unsigned char *)&u16;
|
uc = (unsigned char *)&u16;
|
||||||
for(i=0;i<(data->dc->audioFormat.bits/8);i++) {
|
for (i = 0; i < (data->dc->audioFormat.bits / 8); i++) {
|
||||||
if(data->chunk_length>=FLAC_CHUNK_SIZE) {
|
if (data->chunk_length >= FLAC_CHUNK_SIZE) {
|
||||||
if(flacSendChunk(data)<0) {
|
if (flacSendChunk(data) < 0) {
|
||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
return
|
||||||
|
FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
|
||||||
}
|
}
|
||||||
data->chunk_length = 0;
|
data->chunk_length = 0;
|
||||||
if(data->dc->seek) {
|
if (data->dc->seek) {
|
||||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
return
|
||||||
|
FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data->chunk[data->chunk_length++] = *(uc++);
|
data->chunk[data->chunk_length++] = *(uc++);
|
||||||
@ -206,22 +222,21 @@ static FLAC__StreamDecoderWriteStatus oggflacWrite(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* used by TagDup */
|
/* used by TagDup */
|
||||||
static void of_metadata_dup_cb(
|
static void of_metadata_dup_cb(const OggFLAC__SeekableStreamDecoder * decoder,
|
||||||
const OggFLAC__SeekableStreamDecoder * decoder,
|
const FLAC__StreamMetadata * block, void *vdata)
|
||||||
const FLAC__StreamMetadata *block, void *vdata)
|
|
||||||
{
|
{
|
||||||
FlacData * data = (FlacData *)vdata;
|
FlacData *data = (FlacData *) vdata;
|
||||||
|
|
||||||
switch(block->type) {
|
switch (block->type) {
|
||||||
case FLAC__METADATA_TYPE_STREAMINFO:
|
case FLAC__METADATA_TYPE_STREAMINFO:
|
||||||
if (!data->tag) data->tag = newMpdTag();
|
if (!data->tag)
|
||||||
|
data->tag = newMpdTag();
|
||||||
data->tag->time = ((float)block->data.stream_info.
|
data->tag->time = ((float)block->data.stream_info.
|
||||||
total_samples) /
|
total_samples) /
|
||||||
block->data.stream_info.sample_rate +
|
block->data.stream_info.sample_rate + 0.5;
|
||||||
0.5;
|
|
||||||
return;
|
return;
|
||||||
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
|
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
|
||||||
copyVorbisCommentBlockToMpdTag(block,data->tag);
|
copyVorbisCommentBlockToMpdTag(block, data->tag);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -229,30 +244,30 @@ static void of_metadata_dup_cb(
|
|||||||
|
|
||||||
/* used by decode */
|
/* used by decode */
|
||||||
static void of_metadata_decode_cb(const OggFLAC__SeekableStreamDecoder * dec,
|
static void of_metadata_decode_cb(const OggFLAC__SeekableStreamDecoder * dec,
|
||||||
const FLAC__StreamMetadata *block, void *vdata)
|
const FLAC__StreamMetadata * block,
|
||||||
|
void *vdata)
|
||||||
{
|
{
|
||||||
flac_metadata_common_cb(block, (FlacData *)vdata);
|
flac_metadata_common_cb(block, (FlacData *) vdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
static OggFLAC__SeekableStreamDecoder * full_decoder_init_and_read_metadata(
|
static OggFLAC__SeekableStreamDecoder
|
||||||
FlacData * data,
|
*full_decoder_init_and_read_metadata(FlacData * data,
|
||||||
unsigned int metadata_only)
|
unsigned int metadata_only)
|
||||||
{
|
{
|
||||||
OggFLAC__SeekableStreamDecoder * decoder = NULL;
|
OggFLAC__SeekableStreamDecoder *decoder = NULL;
|
||||||
unsigned int s = 1;
|
unsigned int s = 1;
|
||||||
|
|
||||||
if (!(decoder = OggFLAC__seekable_stream_decoder_new()))
|
if (!(decoder = OggFLAC__seekable_stream_decoder_new()))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (metadata_only) {
|
if (metadata_only) {
|
||||||
s &= OggFLAC__seekable_stream_decoder_set_metadata_callback(
|
s &= OggFLAC__seekable_stream_decoder_set_metadata_callback
|
||||||
decoder, of_metadata_dup_cb);
|
(decoder, of_metadata_dup_cb);
|
||||||
s &= OggFLAC__seekable_stream_decoder_set_metadata_respond(
|
s &= OggFLAC__seekable_stream_decoder_set_metadata_respond
|
||||||
decoder,
|
(decoder, FLAC__METADATA_TYPE_STREAMINFO);
|
||||||
FLAC__METADATA_TYPE_STREAMINFO);
|
|
||||||
} else {
|
} else {
|
||||||
s &= OggFLAC__seekable_stream_decoder_set_metadata_callback(
|
s &= OggFLAC__seekable_stream_decoder_set_metadata_callback
|
||||||
decoder, of_metadata_decode_cb);
|
(decoder, of_metadata_decode_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
s &= OggFLAC__seekable_stream_decoder_set_read_callback(decoder,
|
s &= OggFLAC__seekable_stream_decoder_set_read_callback(decoder,
|
||||||
@ -279,31 +294,30 @@ static OggFLAC__SeekableStreamDecoder * full_decoder_init_and_read_metadata(
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (OggFLAC__seekable_stream_decoder_init(decoder) !=
|
if (OggFLAC__seekable_stream_decoder_init(decoder) !=
|
||||||
OggFLAC__SEEKABLE_STREAM_DECODER_OK)
|
OggFLAC__SEEKABLE_STREAM_DECODER_OK) {
|
||||||
{
|
|
||||||
ERROR("oggflac problem doing init()\n");
|
ERROR("oggflac problem doing init()\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
if (!OggFLAC__seekable_stream_decoder_process_until_end_of_metadata(
|
if (!OggFLAC__seekable_stream_decoder_process_until_end_of_metadata
|
||||||
decoder)) {
|
(decoder)) {
|
||||||
ERROR("oggflac problem reading metadata\n");
|
ERROR("oggflac problem reading metadata\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
return decoder;
|
return decoder;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
oggflacPrintErroredState(
|
oggflacPrintErroredState(OggFLAC__seekable_stream_decoder_get_state
|
||||||
OggFLAC__seekable_stream_decoder_get_state(decoder));
|
(decoder));
|
||||||
OggFLAC__seekable_stream_decoder_delete(decoder);
|
OggFLAC__seekable_stream_decoder_delete(decoder);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* public functions: */
|
/* public functions: */
|
||||||
static MpdTag * oggflac_TagDup(char * file)
|
static MpdTag *oggflac_TagDup(char *file)
|
||||||
{
|
{
|
||||||
InputStream inStream;
|
InputStream inStream;
|
||||||
OggFLAC__SeekableStreamDecoder * decoder;
|
OggFLAC__SeekableStreamDecoder *decoder;
|
||||||
FlacData data;
|
FlacData data;
|
||||||
|
|
||||||
if (openInputStream(&inStream, file) < 0)
|
if (openInputStream(&inStream, file) < 0)
|
||||||
@ -317,7 +331,7 @@ static MpdTag * oggflac_TagDup(char * file)
|
|||||||
|
|
||||||
/* errors here won't matter,
|
/* errors here won't matter,
|
||||||
* data.tag will be set or unset, that's all we care about */
|
* data.tag will be set or unset, that's all we care about */
|
||||||
decoder = full_decoder_init_and_read_metadata(&data,1);
|
decoder = full_decoder_init_and_read_metadata(&data, 1);
|
||||||
|
|
||||||
oggflac_cleanup(&inStream, &data, decoder);
|
oggflac_cleanup(&inStream, &data, decoder);
|
||||||
|
|
||||||
@ -332,49 +346,47 @@ static unsigned int oggflac_try_decode(InputStream * inStream)
|
|||||||
static int oggflac_decode(OutputBuffer * cb, DecoderControl * dc,
|
static int oggflac_decode(OutputBuffer * cb, DecoderControl * dc,
|
||||||
InputStream * inStream)
|
InputStream * inStream)
|
||||||
{
|
{
|
||||||
OggFLAC__SeekableStreamDecoder * decoder = NULL;
|
OggFLAC__SeekableStreamDecoder *decoder = NULL;
|
||||||
FlacData data;
|
FlacData data;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
init_FlacData(&data, cb, dc, inStream);
|
init_FlacData(&data, cb, dc, inStream);
|
||||||
|
|
||||||
if(!(decoder = full_decoder_init_and_read_metadata(&data,0))){
|
if (!(decoder = full_decoder_init_and_read_metadata(&data, 0))) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
OggFLAC__seekable_stream_decoder_process_single(decoder);
|
OggFLAC__seekable_stream_decoder_process_single(decoder);
|
||||||
if(OggFLAC__seekable_stream_decoder_get_state(decoder)!=
|
if (OggFLAC__seekable_stream_decoder_get_state(decoder) !=
|
||||||
OggFLAC__SEEKABLE_STREAM_DECODER_OK)
|
OggFLAC__SEEKABLE_STREAM_DECODER_OK) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(dc->seek) {
|
if (dc->seek) {
|
||||||
FLAC__uint64 sampleToSeek = dc->seekWhere*
|
FLAC__uint64 sampleToSeek = dc->seekWhere *
|
||||||
dc->audioFormat.sampleRate+0.5;
|
dc->audioFormat.sampleRate + 0.5;
|
||||||
if(OggFLAC__seekable_stream_decoder_seek_absolute(
|
if (OggFLAC__seekable_stream_decoder_seek_absolute
|
||||||
decoder, sampleToSeek))
|
(decoder, sampleToSeek)) {
|
||||||
{
|
|
||||||
clearOutputBuffer(cb);
|
clearOutputBuffer(cb);
|
||||||
data.time = ((float)sampleToSeek)/
|
data.time = ((float)sampleToSeek) /
|
||||||
dc->audioFormat.sampleRate;
|
dc->audioFormat.sampleRate;
|
||||||
data.position = 0;
|
data.position = 0;
|
||||||
}
|
} else
|
||||||
else dc->seekError = 1;
|
dc->seekError = 1;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!dc->stop) {
|
if (!dc->stop) {
|
||||||
oggflacPrintErroredState(
|
oggflacPrintErroredState
|
||||||
OggFLAC__seekable_stream_decoder_get_state(decoder));
|
(OggFLAC__seekable_stream_decoder_get_state(decoder));
|
||||||
OggFLAC__seekable_stream_decoder_finish(decoder);
|
OggFLAC__seekable_stream_decoder_finish(decoder);
|
||||||
}
|
}
|
||||||
/* send last little bit */
|
/* send last little bit */
|
||||||
if(data.chunk_length>0 && !dc->stop) {
|
if (data.chunk_length > 0 && !dc->stop) {
|
||||||
flacSendChunk(&data);
|
flacSendChunk(&data);
|
||||||
flushOutputBuffer(data.cb);
|
flushOutputBuffer(data.cb);
|
||||||
}
|
}
|
||||||
@ -382,17 +394,16 @@ static int oggflac_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
oggflac_cleanup(inStream, &data, decoder);
|
oggflac_cleanup(inStream, &data, decoder);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * oggflac_Suffixes[] = {"ogg", NULL};
|
static char *oggflac_Suffixes[] = { "ogg", NULL };
|
||||||
static char * oggflac_mime_types[] = {"application/ogg", NULL};
|
static char *oggflac_mime_types[] = { "application/ogg", NULL };
|
||||||
|
|
||||||
InputPlugin oggflacPlugin =
|
InputPlugin oggflacPlugin = {
|
||||||
{
|
|
||||||
"oggflac",
|
"oggflac",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -407,8 +418,7 @@ InputPlugin oggflacPlugin =
|
|||||||
|
|
||||||
#else /* !HAVE_FLAC */
|
#else /* !HAVE_FLAC */
|
||||||
|
|
||||||
InputPlugin oggflacPlugin =
|
InputPlugin oggflacPlugin = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -422,4 +432,3 @@ InputPlugin oggflacPlugin =
|
|||||||
};
|
};
|
||||||
|
|
||||||
#endif /* HAVE_OGGFLAC */
|
#endif /* HAVE_OGGFLAC */
|
||||||
|
|
||||||
|
@ -61,86 +61,85 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct _OggCallbackData {
|
typedef struct _OggCallbackData {
|
||||||
InputStream * inStream;
|
InputStream *inStream;
|
||||||
DecoderControl * dc;
|
DecoderControl *dc;
|
||||||
} OggCallbackData;
|
} OggCallbackData;
|
||||||
|
|
||||||
static size_t ogg_read_cb(void * ptr, size_t size, size_t nmemb, void * vdata)
|
static size_t ogg_read_cb(void *ptr, size_t size, size_t nmemb, void *vdata)
|
||||||
{
|
{
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
OggCallbackData * data = (OggCallbackData *)vdata;
|
OggCallbackData *data = (OggCallbackData *) vdata;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
ret = readFromInputStream(data->inStream,ptr,size,nmemb);
|
ret = readFromInputStream(data->inStream, ptr, size, nmemb);
|
||||||
if(ret == 0 && !inputStreamAtEOF(data->inStream) &&
|
if (ret == 0 && !inputStreamAtEOF(data->inStream) &&
|
||||||
!data->dc->stop)
|
!data->dc->stop) {
|
||||||
{
|
|
||||||
my_usleep(10000);
|
my_usleep(10000);
|
||||||
}
|
} else
|
||||||
else break;
|
break;
|
||||||
}
|
}
|
||||||
errno = 0;
|
errno = 0;
|
||||||
/*if(ret<0) errno = ((InputStream *)inStream)->error;*/
|
/*if(ret<0) errno = ((InputStream *)inStream)->error; */
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ogg_seek_cb(void * vdata, ogg_int64_t offset, int whence) {
|
static int ogg_seek_cb(void *vdata, ogg_int64_t offset, int whence)
|
||||||
OggCallbackData * data = (OggCallbackData *)vdata;
|
{
|
||||||
|
OggCallbackData *data = (OggCallbackData *) vdata;
|
||||||
|
|
||||||
return seekInputStream(data->inStream,offset,whence);
|
return seekInputStream(data->inStream, offset, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ogg_close_cb(void * vdata) {
|
static int ogg_close_cb(void *vdata)
|
||||||
OggCallbackData * data = (OggCallbackData *)vdata;
|
{
|
||||||
|
OggCallbackData *data = (OggCallbackData *) vdata;
|
||||||
|
|
||||||
return closeInputStream(data->inStream);
|
return closeInputStream(data->inStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
static long ogg_tell_cb(void * vdata) {
|
static long ogg_tell_cb(void *vdata)
|
||||||
OggCallbackData * data = (OggCallbackData *)vdata;
|
{
|
||||||
|
OggCallbackData *data = (OggCallbackData *) vdata;
|
||||||
|
|
||||||
return (long)(data->inStream->offset);
|
return (long)(data->inStream->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * ogg_parseComment(char * comment, char * needle) {
|
static char *ogg_parseComment(char *comment, char *needle)
|
||||||
|
{
|
||||||
int len = strlen(needle);
|
int len = strlen(needle);
|
||||||
|
|
||||||
if(strncasecmp(comment, needle, len) == 0 && *(comment+len) == '=') {
|
if (strncasecmp(comment, needle, len) == 0 && *(comment + len) == '=') {
|
||||||
return comment+len+1;
|
return comment + len + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ogg_getReplayGainInfo(char ** comments, ReplayGainInfo ** infoPtr) {
|
static void ogg_getReplayGainInfo(char **comments, ReplayGainInfo ** infoPtr)
|
||||||
char * temp;
|
{
|
||||||
|
char *temp;
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
|
||||||
if(*infoPtr) freeReplayGainInfo(*infoPtr);
|
if (*infoPtr)
|
||||||
|
freeReplayGainInfo(*infoPtr);
|
||||||
*infoPtr = newReplayGainInfo();
|
*infoPtr = newReplayGainInfo();
|
||||||
|
|
||||||
while(*comments) {
|
while (*comments) {
|
||||||
if((temp = ogg_parseComment(*comments,"replaygain_track_gain")))
|
if ((temp =
|
||||||
{
|
ogg_parseComment(*comments, "replaygain_track_gain"))) {
|
||||||
(*infoPtr)->trackGain = atof(temp);
|
(*infoPtr)->trackGain = atof(temp);
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
} else if ((temp = ogg_parseComment(*comments,
|
||||||
else if((temp = ogg_parseComment(*comments,
|
"replaygain_album_gain"))) {
|
||||||
"replaygain_album_gain")))
|
|
||||||
{
|
|
||||||
(*infoPtr)->albumGain = atof(temp);
|
(*infoPtr)->albumGain = atof(temp);
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
} else if ((temp = ogg_parseComment(*comments,
|
||||||
else if((temp = ogg_parseComment(*comments,
|
"replaygain_track_peak"))) {
|
||||||
"replaygain_track_peak")))
|
|
||||||
{
|
|
||||||
(*infoPtr)->trackPeak = atof(temp);
|
(*infoPtr)->trackPeak = atof(temp);
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
} else if ((temp = ogg_parseComment(*comments,
|
||||||
else if((temp = ogg_parseComment(*comments,
|
"replaygain_album_peak"))) {
|
||||||
"replaygain_album_peak")))
|
|
||||||
{
|
|
||||||
(*infoPtr)->albumPeak = atof(temp);
|
(*infoPtr)->albumPeak = atof(temp);
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
@ -148,32 +147,38 @@ static void ogg_getReplayGainInfo(char ** comments, ReplayGainInfo ** infoPtr) {
|
|||||||
comments++;
|
comments++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!found) {
|
if (!found) {
|
||||||
freeReplayGainInfo(*infoPtr);
|
freeReplayGainInfo(*infoPtr);
|
||||||
*infoPtr = NULL;
|
*infoPtr = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * VORBIS_COMMENT_TRACK_KEY = "tracknumber";
|
static const char *VORBIS_COMMENT_TRACK_KEY = "tracknumber";
|
||||||
static const char * VORBIS_COMMENT_DISC_KEY = "discnumber";
|
static const char *VORBIS_COMMENT_DISC_KEY = "discnumber";
|
||||||
|
|
||||||
static unsigned int ogg_parseCommentAddToTag(char * comment,
|
static unsigned int ogg_parseCommentAddToTag(char *comment,
|
||||||
unsigned int itemType, MpdTag ** tag)
|
unsigned int itemType,
|
||||||
|
MpdTag ** tag)
|
||||||
{
|
{
|
||||||
const char * needle;
|
const char *needle;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
switch (itemType) {
|
switch (itemType) {
|
||||||
case TAG_ITEM_TRACK: needle = VORBIS_COMMENT_TRACK_KEY; break;
|
case TAG_ITEM_TRACK:
|
||||||
case TAG_ITEM_DISC: needle = VORBIS_COMMENT_DISC_KEY; break;
|
needle = VORBIS_COMMENT_TRACK_KEY;
|
||||||
default: needle = mpdTagItemKeys[itemType];
|
break;
|
||||||
|
case TAG_ITEM_DISC:
|
||||||
|
needle = VORBIS_COMMENT_DISC_KEY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
needle = mpdTagItemKeys[itemType];
|
||||||
}
|
}
|
||||||
len = strlen(needle);
|
len = strlen(needle);
|
||||||
|
|
||||||
if(strncasecmp(comment, needle, len) == 0 && *(comment+len) == '=') {
|
if (strncasecmp(comment, needle, len) == 0 && *(comment + len) == '=') {
|
||||||
if (!*tag)
|
if (!*tag)
|
||||||
*tag = newMpdTag();
|
*tag = newMpdTag();
|
||||||
|
|
||||||
addItemToMpdTag(*tag, itemType, comment+len+1);
|
addItemToMpdTag(*tag, itemType, comment + len + 1);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -181,12 +186,13 @@ static unsigned int ogg_parseCommentAddToTag(char * comment,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * oggCommentsParse(char ** comments) {
|
static MpdTag *oggCommentsParse(char **comments)
|
||||||
MpdTag * tag = NULL;
|
{
|
||||||
|
MpdTag *tag = NULL;
|
||||||
|
|
||||||
while(*comments) {
|
while (*comments) {
|
||||||
int j;
|
int j;
|
||||||
for (j = TAG_NUM_OF_ITEM_TYPES; --j >= 0; ) {
|
for (j = TAG_NUM_OF_ITEM_TYPES; --j >= 0;) {
|
||||||
if (ogg_parseCommentAddToTag(*comments, j, &tag))
|
if (ogg_parseCommentAddToTag(*comments, j, &tag))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -196,23 +202,24 @@ static MpdTag * oggCommentsParse(char ** comments) {
|
|||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void putOggCommentsIntoOutputBuffer(OutputBuffer * cb, char * streamName,
|
static void putOggCommentsIntoOutputBuffer(OutputBuffer * cb, char *streamName,
|
||||||
char ** comments)
|
char **comments)
|
||||||
{
|
{
|
||||||
MpdTag * tag;
|
MpdTag *tag;
|
||||||
|
|
||||||
tag = oggCommentsParse(comments);
|
tag = oggCommentsParse(comments);
|
||||||
if(!tag && streamName) {
|
if (!tag && streamName) {
|
||||||
tag = newMpdTag();
|
tag = newMpdTag();
|
||||||
}
|
}
|
||||||
if(!tag) return;
|
if (!tag)
|
||||||
|
return;
|
||||||
|
|
||||||
/*if(tag->artist) printf("Artist: %s\n", tag->artist);
|
/*if(tag->artist) printf("Artist: %s\n", tag->artist);
|
||||||
if(tag->album) printf("Album: %s\n", tag->album);
|
if(tag->album) printf("Album: %s\n", tag->album);
|
||||||
if(tag->track) printf("Track: %s\n", tag->track);
|
if(tag->track) printf("Track: %s\n", tag->track);
|
||||||
if(tag->title) printf("Title: %s\n", tag->title);*/
|
if(tag->title) printf("Title: %s\n", tag->title); */
|
||||||
|
|
||||||
if(streamName) {
|
if (streamName) {
|
||||||
clearItemsFromMpdTag(tag, TAG_ITEM_NAME);
|
clearItemsFromMpdTag(tag, TAG_ITEM_NAME);
|
||||||
addItemToMpdTag(tag, TAG_ITEM_NAME, streamName);
|
addItemToMpdTag(tag, TAG_ITEM_NAME, streamName);
|
||||||
}
|
}
|
||||||
@ -238,9 +245,9 @@ static int oggvorbis_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
int chunkpos = 0;
|
int chunkpos = 0;
|
||||||
long bitRate = 0;
|
long bitRate = 0;
|
||||||
long test;
|
long test;
|
||||||
ReplayGainInfo * replayGainInfo = NULL;
|
ReplayGainInfo *replayGainInfo = NULL;
|
||||||
char ** comments;
|
char **comments;
|
||||||
char * errorStr;
|
char *errorStr;
|
||||||
|
|
||||||
data.inStream = inStream;
|
data.inStream = inStream;
|
||||||
data.dc = dc;
|
data.dc = dc;
|
||||||
@ -250,10 +257,10 @@ static int oggvorbis_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
callbacks.close_func = ogg_close_cb;
|
callbacks.close_func = ogg_close_cb;
|
||||||
callbacks.tell_func = ogg_tell_cb;
|
callbacks.tell_func = ogg_tell_cb;
|
||||||
|
|
||||||
if((ret = ov_open_callbacks(&data, &vf, NULL, 0, callbacks)) < 0) {
|
if ((ret = ov_open_callbacks(&data, &vf, NULL, 0, callbacks)) < 0) {
|
||||||
closeInputStream(inStream);
|
closeInputStream(inStream);
|
||||||
if(!dc->stop) {
|
if (!dc->stop) {
|
||||||
switch(ret) {
|
switch (ret) {
|
||||||
case OV_EREAD:
|
case OV_EREAD:
|
||||||
errorStr = "read error";
|
errorStr = "read error";
|
||||||
break;
|
break;
|
||||||
@ -276,39 +283,38 @@ static int oggvorbis_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
ERROR("Error decoding Ogg Vorbis stream: %s\n",
|
ERROR("Error decoding Ogg Vorbis stream: %s\n",
|
||||||
errorStr);
|
errorStr);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dc->totalTime = ov_time_total(&vf,-1);
|
dc->totalTime = ov_time_total(&vf, -1);
|
||||||
if(dc->totalTime < 0) dc->totalTime = 0;
|
if (dc->totalTime < 0)
|
||||||
|
dc->totalTime = 0;
|
||||||
|
|
||||||
dc->audioFormat.bits = 16;
|
dc->audioFormat.bits = 16;
|
||||||
|
|
||||||
while(!eof) {
|
while (!eof) {
|
||||||
if(dc->seek) {
|
if (dc->seek) {
|
||||||
if(0 == ov_time_seek_page(&vf,dc->seekWhere)) {
|
if (0 == ov_time_seek_page(&vf, dc->seekWhere)) {
|
||||||
clearOutputBuffer(cb);
|
clearOutputBuffer(cb);
|
||||||
chunkpos = 0;
|
chunkpos = 0;
|
||||||
}
|
} else
|
||||||
else dc->seekError = 1;
|
dc->seekError = 1;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
ret = ov_read(&vf, chunk+chunkpos,
|
ret = ov_read(&vf, chunk + chunkpos,
|
||||||
OGG_CHUNK_SIZE-chunkpos,
|
OGG_CHUNK_SIZE - chunkpos,
|
||||||
OGG_DECODE_USE_BIGENDIAN,
|
OGG_DECODE_USE_BIGENDIAN, 2, 1, ¤t_section);
|
||||||
2, 1, ¤t_section);
|
|
||||||
|
|
||||||
if(current_section!=prev_section) {
|
if (current_section != prev_section) {
|
||||||
/*printf("new song!\n");*/
|
/*printf("new song!\n"); */
|
||||||
vorbis_info *vi=ov_info(&vf,-1);
|
vorbis_info *vi = ov_info(&vf, -1);
|
||||||
dc->audioFormat.channels = vi->channels;
|
dc->audioFormat.channels = vi->channels;
|
||||||
dc->audioFormat.sampleRate = vi->rate;
|
dc->audioFormat.sampleRate = vi->rate;
|
||||||
if(dc->state == DECODE_STATE_START) {
|
if (dc->state == DECODE_STATE_START) {
|
||||||
getOutputAudioFormat(&(dc->audioFormat),
|
getOutputAudioFormat(&(dc->audioFormat),
|
||||||
&(cb->audioFormat));
|
&(cb->audioFormat));
|
||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
@ -321,71 +327,76 @@ static int oggvorbis_decode(OutputBuffer * cb, DecoderControl * dc,
|
|||||||
|
|
||||||
prev_section = current_section;
|
prev_section = current_section;
|
||||||
|
|
||||||
if(ret <= 0 && ret != OV_HOLE) {
|
if (ret <= 0 && ret != OV_HOLE) {
|
||||||
eof = 1;
|
eof = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(ret == OV_HOLE) ret = 0;
|
if (ret == OV_HOLE)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
chunkpos+=ret;
|
chunkpos += ret;
|
||||||
|
|
||||||
if(chunkpos >= OGG_CHUNK_SIZE) {
|
if (chunkpos >= OGG_CHUNK_SIZE) {
|
||||||
if((test = ov_bitrate_instant(&vf))>0) {
|
if ((test = ov_bitrate_instant(&vf)) > 0) {
|
||||||
bitRate = test/1000;
|
bitRate = test / 1000;
|
||||||
}
|
}
|
||||||
sendDataToOutputBuffer(cb, inStream, dc,
|
sendDataToOutputBuffer(cb, inStream, dc,
|
||||||
inStream->seekable,
|
inStream->seekable,
|
||||||
chunk, chunkpos,
|
chunk, chunkpos,
|
||||||
ov_pcm_tell(&vf)/
|
ov_pcm_tell(&vf) /
|
||||||
dc->audioFormat.sampleRate,
|
dc->audioFormat.sampleRate,
|
||||||
bitRate,
|
bitRate, replayGainInfo);
|
||||||
replayGainInfo);
|
|
||||||
chunkpos = 0;
|
chunkpos = 0;
|
||||||
if(dc->stop) break;
|
if (dc->stop)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!dc->stop && chunkpos > 0) {
|
if (!dc->stop && chunkpos > 0) {
|
||||||
sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
|
sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
|
||||||
chunk, chunkpos,
|
chunk, chunkpos,
|
||||||
ov_time_tell(&vf), bitRate, replayGainInfo);
|
ov_time_tell(&vf), bitRate,
|
||||||
|
replayGainInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(replayGainInfo) freeReplayGainInfo(replayGainInfo);
|
if (replayGainInfo)
|
||||||
|
freeReplayGainInfo(replayGainInfo);
|
||||||
|
|
||||||
ov_clear(&vf);
|
ov_clear(&vf);
|
||||||
|
|
||||||
flushOutputBuffer(cb);
|
flushOutputBuffer(cb);
|
||||||
|
|
||||||
if(dc->stop) {
|
if (dc->stop) {
|
||||||
dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
dc->stop = 0;
|
dc->stop = 0;
|
||||||
}
|
} else
|
||||||
else dc->state = DECODE_STATE_STOP;
|
dc->state = DECODE_STATE_STOP;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static MpdTag * oggvorbis_TagDup(char * file) {
|
static MpdTag *oggvorbis_TagDup(char *file)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
FILE * fp;
|
MpdTag *ret = NULL;
|
||||||
|
FILE *fp;
|
||||||
OggVorbis_File vf;
|
OggVorbis_File vf;
|
||||||
|
|
||||||
fp = fopen(file,"r");
|
fp = fopen(file, "r");
|
||||||
if(!fp)
|
if (!fp) {
|
||||||
{
|
DEBUG("oggTagDup: Failed to open file: '%s', %s\n", file,
|
||||||
DEBUG("oggTagDup: Failed to open file: '%s', %s\n", file, strerror(errno));
|
strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(ov_open(fp,&vf,NULL,0)<0) {
|
if (ov_open(fp, &vf, NULL, 0) < 0) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = oggCommentsParse(ov_comment(&vf,-1)->user_comments);
|
ret = oggCommentsParse(ov_comment(&vf, -1)->user_comments);
|
||||||
|
|
||||||
if(!ret) ret = newMpdTag();
|
if (!ret)
|
||||||
ret->time = (int)(ov_time_total(&vf,-1)+0.5);
|
ret = newMpdTag();
|
||||||
|
ret->time = (int)(ov_time_total(&vf, -1) + 0.5);
|
||||||
|
|
||||||
ov_clear(&vf);
|
ov_clear(&vf);
|
||||||
|
|
||||||
@ -397,12 +408,10 @@ static unsigned int oggvorbis_try_decode(InputStream * inStream)
|
|||||||
return (ogg_stream_type_detect(inStream) == VORBIS) ? 1 : 0;
|
return (ogg_stream_type_detect(inStream) == VORBIS) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *oggvorbis_Suffixes[] = { "ogg", NULL };
|
||||||
|
static char *oggvorbis_MimeTypes[] = { "application/ogg", NULL };
|
||||||
|
|
||||||
static char * oggvorbis_Suffixes[] = {"ogg", NULL};
|
InputPlugin oggvorbisPlugin = {
|
||||||
static char * oggvorbis_MimeTypes[] = {"application/ogg", NULL};
|
|
||||||
|
|
||||||
InputPlugin oggvorbisPlugin =
|
|
||||||
{
|
|
||||||
"oggvorbis",
|
"oggvorbis",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -417,8 +426,7 @@ InputPlugin oggvorbisPlugin =
|
|||||||
|
|
||||||
#else /* !HAVE_OGGVORBIS */
|
#else /* !HAVE_OGGVORBIS */
|
||||||
|
|
||||||
InputPlugin oggvorbisPlugin =
|
InputPlugin oggvorbisPlugin = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -25,12 +25,14 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
void initInputStream(void) {
|
void initInputStream(void)
|
||||||
|
{
|
||||||
inputStream_initFile();
|
inputStream_initFile();
|
||||||
inputStream_initHttp();
|
inputStream_initHttp();
|
||||||
}
|
}
|
||||||
|
|
||||||
int openInputStream(InputStream * inStream, char * url) {
|
int openInputStream(InputStream * inStream, char *url)
|
||||||
|
{
|
||||||
inStream->offset = 0;
|
inStream->offset = 0;
|
||||||
inStream->size = 0;
|
inStream->size = 0;
|
||||||
inStream->error = 0;
|
inStream->error = 0;
|
||||||
@ -39,34 +41,43 @@ int openInputStream(InputStream * inStream, char * url) {
|
|||||||
inStream->metaName = NULL;
|
inStream->metaName = NULL;
|
||||||
inStream->metaTitle = NULL;
|
inStream->metaTitle = NULL;
|
||||||
|
|
||||||
if(inputStream_fileOpen(inStream,url) == 0) return 0;
|
if (inputStream_fileOpen(inStream, url) == 0)
|
||||||
if(inputStream_httpOpen(inStream,url) == 0) return 0;
|
return 0;
|
||||||
|
if (inputStream_httpOpen(inStream, url) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int seekInputStream(InputStream * inStream, long offset, int whence) {
|
int seekInputStream(InputStream * inStream, long offset, int whence)
|
||||||
return inStream->seekFunc(inStream,offset,whence);
|
{
|
||||||
|
return inStream->seekFunc(inStream, offset, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t readFromInputStream(InputStream * inStream, void * ptr, size_t size,
|
size_t readFromInputStream(InputStream * inStream, void *ptr, size_t size,
|
||||||
size_t nmemb)
|
size_t nmemb)
|
||||||
{
|
{
|
||||||
return inStream->readFunc(inStream,ptr,size,nmemb);
|
return inStream->readFunc(inStream, ptr, size, nmemb);
|
||||||
}
|
}
|
||||||
|
|
||||||
int closeInputStream(InputStream * inStream) {
|
int closeInputStream(InputStream * inStream)
|
||||||
if(inStream->mime) free(inStream->mime);
|
{
|
||||||
if(inStream->metaName) free(inStream->metaName);
|
if (inStream->mime)
|
||||||
if(inStream->metaTitle) free(inStream->metaTitle);
|
free(inStream->mime);
|
||||||
|
if (inStream->metaName)
|
||||||
|
free(inStream->metaName);
|
||||||
|
if (inStream->metaTitle)
|
||||||
|
free(inStream->metaTitle);
|
||||||
|
|
||||||
return inStream->closeFunc(inStream);
|
return inStream->closeFunc(inStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
int inputStreamAtEOF(InputStream * inStream) {
|
int inputStreamAtEOF(InputStream * inStream)
|
||||||
|
{
|
||||||
return inStream->atEOFFunc(inStream);
|
return inStream->atEOFFunc(inStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bufferInputStream(InputStream * inStream) {
|
int bufferInputStream(InputStream * inStream)
|
||||||
|
{
|
||||||
return inStream->bufferFunc(inStream);
|
return inStream->bufferFunc(inStream);
|
||||||
}
|
}
|
||||||
|
@ -23,19 +23,19 @@
|
|||||||
|
|
||||||
typedef struct _InputStream InputStream;
|
typedef struct _InputStream InputStream;
|
||||||
|
|
||||||
typedef int (* InputStreamSeekFunc) (InputStream * inStream, long offset,
|
typedef int (*InputStreamSeekFunc) (InputStream * inStream, long offset,
|
||||||
int whence);
|
int whence);
|
||||||
typedef size_t (* InputStreamReadFunc) (InputStream * inStream, void * ptr, size_t size,
|
typedef size_t(*InputStreamReadFunc) (InputStream * inStream, void *ptr,
|
||||||
size_t nmemb);
|
size_t size, size_t nmemb);
|
||||||
typedef int (* InputStreamCloseFunc) (InputStream * inStream);
|
typedef int (*InputStreamCloseFunc) (InputStream * inStream);
|
||||||
typedef int (* InputStreamAtEOFFunc) (InputStream * inStream);
|
typedef int (*InputStreamAtEOFFunc) (InputStream * inStream);
|
||||||
typedef int (* InputStreamBufferFunc) (InputStream * inStream);
|
typedef int (*InputStreamBufferFunc) (InputStream * inStream);
|
||||||
|
|
||||||
struct _InputStream {
|
struct _InputStream {
|
||||||
int error;
|
int error;
|
||||||
long offset;
|
long offset;
|
||||||
size_t size;
|
size_t size;
|
||||||
char * mime;
|
char *mime;
|
||||||
int seekable;
|
int seekable;
|
||||||
|
|
||||||
/* don't touc this stuff */
|
/* don't touc this stuff */
|
||||||
@ -44,18 +44,18 @@ struct _InputStream {
|
|||||||
InputStreamCloseFunc closeFunc;
|
InputStreamCloseFunc closeFunc;
|
||||||
InputStreamAtEOFFunc atEOFFunc;
|
InputStreamAtEOFFunc atEOFFunc;
|
||||||
InputStreamBufferFunc bufferFunc;
|
InputStreamBufferFunc bufferFunc;
|
||||||
void * data;
|
void *data;
|
||||||
char * metaName;
|
char *metaName;
|
||||||
char * metaTitle;
|
char *metaTitle;
|
||||||
};
|
};
|
||||||
|
|
||||||
void initInputStream();
|
void initInputStream();
|
||||||
|
|
||||||
int isUrlSaneForInputStream(char * url);
|
int isUrlSaneForInputStream(char *url);
|
||||||
|
|
||||||
/* if an error occurs for these 3 functions, then -1 is returned and errno
|
/* if an error occurs for these 3 functions, then -1 is returned and errno
|
||||||
for the input stream is set */
|
for the input stream is set */
|
||||||
int openInputStream(InputStream * inStream, char * url);
|
int openInputStream(InputStream * inStream, char *url);
|
||||||
int seekInputStream(InputStream * inStream, long offset, int whence);
|
int seekInputStream(InputStream * inStream, long offset, int whence);
|
||||||
int closeInputStream(InputStream * inStream);
|
int closeInputStream(InputStream * inStream);
|
||||||
int inputStreamAtEOF(InputStream * inStream);
|
int inputStreamAtEOF(InputStream * inStream);
|
||||||
@ -64,7 +64,7 @@ int inputStreamAtEOF(InputStream * inStream);
|
|||||||
was buffered */
|
was buffered */
|
||||||
int bufferInputStream(InputStream * inStream);
|
int bufferInputStream(InputStream * inStream);
|
||||||
|
|
||||||
size_t readFromInputStream(InputStream * inStream, void * ptr, size_t size,
|
size_t readFromInputStream(InputStream * inStream, void *ptr, size_t size,
|
||||||
size_t nmemb);
|
size_t nmemb);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,23 +26,25 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
void inputStream_initFile(void) {
|
void inputStream_initFile(void)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int inputStream_fileOpen(InputStream * inStream, char * filename) {
|
int inputStream_fileOpen(InputStream * inStream, char *filename)
|
||||||
FILE * fp;
|
{
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopen(filename,"r");
|
fp = fopen(filename, "r");
|
||||||
if(!fp) {
|
if (!fp) {
|
||||||
inStream->error = errno;
|
inStream->error = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inStream->seekable = 1;
|
inStream->seekable = 1;
|
||||||
|
|
||||||
fseek(fp,0,SEEK_END);
|
fseek(fp, 0, SEEK_END);
|
||||||
inStream->size = ftell(fp);
|
inStream->size = ftell(fp);
|
||||||
fseek(fp,0,SEEK_SET);
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
inStream->data = fp;
|
inStream->data = fp;
|
||||||
inStream->seekFunc = inputStream_fileSeek;
|
inStream->seekFunc = inputStream_fileSeek;
|
||||||
@ -54,11 +56,11 @@ int inputStream_fileOpen(InputStream * inStream, char * filename) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inputStream_fileSeek(InputStream * inStream, long offset, int whence) {
|
int inputStream_fileSeek(InputStream * inStream, long offset, int whence)
|
||||||
if(fseek((FILE *)inStream->data,offset,whence)==0) {
|
{
|
||||||
inStream->offset = ftell((FILE *)inStream->data);
|
if (fseek((FILE *) inStream->data, offset, whence) == 0) {
|
||||||
}
|
inStream->offset = ftell((FILE *) inStream->data);
|
||||||
else {
|
} else {
|
||||||
inStream->error = errno;
|
inStream->error = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -66,25 +68,26 @@ int inputStream_fileSeek(InputStream * inStream, long offset, int whence) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t inputStream_fileRead(InputStream * inStream, void * ptr, size_t size,
|
size_t inputStream_fileRead(InputStream * inStream, void *ptr, size_t size,
|
||||||
size_t nmemb)
|
size_t nmemb)
|
||||||
{
|
{
|
||||||
size_t readSize;
|
size_t readSize;
|
||||||
|
|
||||||
readSize = fread(ptr,size,nmemb,(FILE *)inStream->data);
|
readSize = fread(ptr, size, nmemb, (FILE *) inStream->data);
|
||||||
if(readSize <=0 && ferror((FILE *)inStream->data)) {
|
if (readSize <= 0 && ferror((FILE *) inStream->data)) {
|
||||||
inStream->error = errno;
|
inStream->error = errno;
|
||||||
DEBUG("inputStream_fileRead: error reading: %s\n",
|
DEBUG("inputStream_fileRead: error reading: %s\n",
|
||||||
strerror(inStream->error));
|
strerror(inStream->error));
|
||||||
}
|
}
|
||||||
|
|
||||||
inStream->offset = ftell((FILE *)inStream->data);
|
inStream->offset = ftell((FILE *) inStream->data);
|
||||||
|
|
||||||
return readSize;
|
return readSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inputStream_fileClose(InputStream * inStream) {
|
int inputStream_fileClose(InputStream * inStream)
|
||||||
if(fclose((FILE *)inStream->data)<0) {
|
{
|
||||||
|
if (fclose((FILE *) inStream->data) < 0) {
|
||||||
inStream->error = errno;
|
inStream->error = errno;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -92,16 +95,19 @@ int inputStream_fileClose(InputStream * inStream) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inputStream_fileAtEOF(InputStream * inStream) {
|
int inputStream_fileAtEOF(InputStream * inStream)
|
||||||
if(feof((FILE *)inStream->data)) return 1;
|
{
|
||||||
|
if (feof((FILE *) inStream->data))
|
||||||
|
return 1;
|
||||||
|
|
||||||
if(ferror((FILE *)inStream->data) && inStream->error != EINTR) {
|
if (ferror((FILE *) inStream->data) && inStream->error != EINTR) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inputStream_fileBuffer(InputStream * inStream) {
|
int inputStream_fileBuffer(InputStream * inStream)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,11 @@
|
|||||||
|
|
||||||
void inputStream_initFile();
|
void inputStream_initFile();
|
||||||
|
|
||||||
int inputStream_fileOpen(InputStream * inStream, char * filename);
|
int inputStream_fileOpen(InputStream * inStream, char *filename);
|
||||||
|
|
||||||
int inputStream_fileSeek(InputStream * inStream, long offset, int whence);
|
int inputStream_fileSeek(InputStream * inStream, long offset, int whence);
|
||||||
|
|
||||||
size_t inputStream_fileRead(InputStream * inStream, void * ptr, size_t size,
|
size_t inputStream_fileRead(InputStream * inStream, void *ptr, size_t size,
|
||||||
size_t nmemb);
|
size_t nmemb);
|
||||||
|
|
||||||
int inputStream_fileClose(InputStream * inStream);
|
int inputStream_fileClose(InputStream * inStream);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -23,11 +23,11 @@
|
|||||||
|
|
||||||
void inputStream_initHttp();
|
void inputStream_initHttp();
|
||||||
|
|
||||||
int inputStream_httpOpen(InputStream * inStream, char * filename);
|
int inputStream_httpOpen(InputStream * inStream, char *filename);
|
||||||
|
|
||||||
int inputStream_httpSeek(InputStream * inStream, long offset, int whence);
|
int inputStream_httpSeek(InputStream * inStream, long offset, int whence);
|
||||||
|
|
||||||
size_t inputStream_httpRead(InputStream * inStream, void * ptr, size_t size,
|
size_t inputStream_httpRead(InputStream * inStream, void *ptr, size_t size,
|
||||||
size_t nmemb);
|
size_t nmemb);
|
||||||
|
|
||||||
int inputStream_httpClose(InputStream * inStream);
|
int inputStream_httpClose(InputStream * inStream);
|
||||||
|
492
src/interface.c
492
src/interface.c
@ -54,7 +54,7 @@
|
|||||||
#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024)
|
#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024)
|
||||||
|
|
||||||
/* set this to zero to indicate we have no possible interfaces */
|
/* set this to zero to indicate we have no possible interfaces */
|
||||||
static int interface_max_connections = 0; /*INTERFACE_MAX_CONNECTIONS_DEFAULT;*/
|
static int interface_max_connections = 0; /*INTERFACE_MAX_CONNECTIONS_DEFAULT; */
|
||||||
static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT;
|
static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT;
|
||||||
static size_t interface_max_command_list_size =
|
static size_t interface_max_command_list_size =
|
||||||
INTERFACE_MAX_COMMAND_LIST_DEFAULT;
|
INTERFACE_MAX_COMMAND_LIST_DEFAULT;
|
||||||
@ -66,42 +66,43 @@ typedef struct _Interface {
|
|||||||
int bufferLength;
|
int bufferLength;
|
||||||
int bufferPos;
|
int bufferPos;
|
||||||
int fd; /* file descriptor */
|
int fd; /* file descriptor */
|
||||||
FILE * fp; /* file pointer */
|
FILE *fp; /* file pointer */
|
||||||
int open; /* open/used */
|
int open; /* open/used */
|
||||||
int permission;
|
int permission;
|
||||||
time_t lastTime;
|
time_t lastTime;
|
||||||
List * commandList; /* for when in list mode */
|
List *commandList; /* for when in list mode */
|
||||||
int commandListOK; /* print OK after each command execution */
|
int commandListOK; /* print OK after each command execution */
|
||||||
size_t commandListSize; /* mem commandList consumes */
|
size_t commandListSize; /* mem commandList consumes */
|
||||||
List * bufferList; /* for output if client is slow */
|
List *bufferList; /* for output if client is slow */
|
||||||
size_t outputBufferSize; /* mem bufferList consumes */
|
size_t outputBufferSize; /* mem bufferList consumes */
|
||||||
int expired; /* set whether this interface should be closed on next
|
int expired; /* set whether this interface should be closed on next
|
||||||
check of old interfaces */
|
check of old interfaces */
|
||||||
int num; /* interface number */
|
int num; /* interface number */
|
||||||
char * outBuffer;
|
char *outBuffer;
|
||||||
int outBuflen;
|
int outBuflen;
|
||||||
int outBufSize;
|
int outBufSize;
|
||||||
} Interface;
|
} Interface;
|
||||||
|
|
||||||
static Interface * interfaces = NULL;
|
static Interface *interfaces = NULL;
|
||||||
|
|
||||||
static void flushInterfaceBuffer(Interface * interface);
|
static void flushInterfaceBuffer(Interface * interface);
|
||||||
|
|
||||||
static void printInterfaceOutBuffer(Interface * interface);
|
static void printInterfaceOutBuffer(Interface * interface);
|
||||||
|
|
||||||
static void openInterface(Interface * interface, int fd) {
|
static void openInterface(Interface * interface, int fd)
|
||||||
|
{
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
assert(interface->open==0);
|
assert(interface->open == 0);
|
||||||
|
|
||||||
interface->bufferLength = 0;
|
interface->bufferLength = 0;
|
||||||
interface->bufferPos = 0;
|
interface->bufferPos = 0;
|
||||||
interface->fd = fd;
|
interface->fd = fd;
|
||||||
/* fcntl(interface->fd,F_SETOWN,(int)getpid()); */
|
/* fcntl(interface->fd,F_SETOWN,(int)getpid()); */
|
||||||
while((flags = fcntl(fd,F_GETFL))<0 && errno==EINTR);
|
while ((flags = fcntl(fd, F_GETFL)) < 0 && errno == EINTR) ;
|
||||||
flags|=O_NONBLOCK;
|
flags |= O_NONBLOCK;
|
||||||
while(fcntl(interface->fd,F_SETFL,flags)<0 && errno==EINTR);
|
while (fcntl(interface->fd, F_SETFL, flags) < 0 && errno == EINTR) ;
|
||||||
while((interface->fp = fdopen(fd,"rw"))==NULL && errno==EINTR);
|
while ((interface->fp = fdopen(fd, "rw")) == NULL && errno == EINTR) ;
|
||||||
interface->open = 1;
|
interface->open = 1;
|
||||||
interface->lastTime = time(NULL);
|
interface->lastTime = time(NULL);
|
||||||
interface->commandList = NULL;
|
interface->commandList = NULL;
|
||||||
@ -118,15 +119,13 @@ static void openInterface(Interface * interface, int fd) {
|
|||||||
int getSize;
|
int getSize;
|
||||||
unsigned int sockOptLen = sizeof(int);
|
unsigned int sockOptLen = sizeof(int);
|
||||||
|
|
||||||
if(getsockopt(interface->fd,SOL_SOCKET,SO_SNDBUF,
|
if (getsockopt(interface->fd, SOL_SOCKET, SO_SNDBUF,
|
||||||
(char *)&getSize,&sockOptLen) < 0)
|
(char *)&getSize, &sockOptLen) < 0) {
|
||||||
{
|
|
||||||
DEBUG("problem getting sockets send buffer size\n");
|
DEBUG("problem getting sockets send buffer size\n");
|
||||||
}
|
} else if (getSize <= 0) {
|
||||||
else if(getSize<=0) {
|
|
||||||
DEBUG("sockets send buffer size is not positive\n");
|
DEBUG("sockets send buffer size is not positive\n");
|
||||||
}
|
} else
|
||||||
else interface->outBufSize = getSize;
|
interface->outBufSize = getSize;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
interface->outBuffer = malloc(interface->outBufSize);
|
interface->outBuffer = malloc(interface->outBufSize);
|
||||||
@ -135,42 +134,44 @@ static void openInterface(Interface * interface, int fd) {
|
|||||||
printInterfaceOutBuffer(interface);
|
printInterfaceOutBuffer(interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void closeInterface(Interface * interface) {
|
static void closeInterface(Interface * interface)
|
||||||
if (!interface->open) return;
|
{
|
||||||
|
if (!interface->open)
|
||||||
|
return;
|
||||||
|
|
||||||
interface->open = 0;
|
interface->open = 0;
|
||||||
|
|
||||||
while(fclose(interface->fp) && errno==EINTR);
|
while (fclose(interface->fp) && errno == EINTR) ;
|
||||||
|
|
||||||
if(interface->commandList) freeList(interface->commandList);
|
if (interface->commandList)
|
||||||
if(interface->bufferList) freeList(interface->bufferList);
|
freeList(interface->commandList);
|
||||||
|
if (interface->bufferList)
|
||||||
|
freeList(interface->bufferList);
|
||||||
|
|
||||||
free(interface->outBuffer);
|
free(interface->outBuffer);
|
||||||
|
|
||||||
SECURE("interface %i: closed\n",interface->num);
|
SECURE("interface %i: closed\n", interface->num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void openAInterface(int fd, struct sockaddr * addr) {
|
void openAInterface(int fd, struct sockaddr *addr)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0;i<interface_max_connections && interfaces[i].open;i++);
|
for (i = 0; i < interface_max_connections && interfaces[i].open; i++) ;
|
||||||
|
|
||||||
if(i==interface_max_connections) {
|
if (i == interface_max_connections) {
|
||||||
ERROR("Max Connections Reached!\n");
|
ERROR("Max Connections Reached!\n");
|
||||||
while(close(fd) && errno==EINTR);
|
while (close(fd) && errno == EINTR) ;
|
||||||
}
|
} else {
|
||||||
else {
|
SECURE("interface %i: opened from ", i);
|
||||||
SECURE("interface %i: opened from ",i);
|
switch (addr->sa_family) {
|
||||||
switch(addr->sa_family) {
|
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
{
|
{
|
||||||
char * host = inet_ntoa(
|
char *host = inet_ntoa(((struct sockaddr_in *)
|
||||||
((struct sockaddr_in *)addr)->
|
addr)->sin_addr);
|
||||||
sin_addr);
|
if (host) {
|
||||||
if(host) {
|
SECURE("%s\n", host);
|
||||||
SECURE("%s\n",host);
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
SECURE("error getting ipv4 address\n");
|
SECURE("error getting ipv4 address\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,15 +179,14 @@ void openAInterface(int fd, struct sockaddr * addr) {
|
|||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
{
|
{
|
||||||
char host[INET6_ADDRSTRLEN+1];
|
char host[INET6_ADDRSTRLEN + 1];
|
||||||
memset(host,0,INET6_ADDRSTRLEN+1);
|
memset(host, 0, INET6_ADDRSTRLEN + 1);
|
||||||
if(inet_ntop(AF_INET6,(void *)
|
if (inet_ntop(AF_INET6, (void *)
|
||||||
&(((struct sockaddr_in6 *)addr)->
|
&(((struct sockaddr_in6 *)addr)->
|
||||||
sin6_addr),host,INET6_ADDRSTRLEN))
|
sin6_addr), host,
|
||||||
{
|
INET6_ADDRSTRLEN)) {
|
||||||
SECURE("%s\n",host);
|
SECURE("%s\n", host);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
SECURE("error getting ipv6 address\n");
|
SECURE("error getting ipv6 address\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,37 +198,36 @@ void openAInterface(int fd, struct sockaddr * addr) {
|
|||||||
default:
|
default:
|
||||||
SECURE("unknown\n");
|
SECURE("unknown\n");
|
||||||
}
|
}
|
||||||
openInterface(&(interfaces[i]),fd);
|
openInterface(&(interfaces[i]), fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int processLineOfInput(Interface * interface) {
|
static int processLineOfInput(Interface * interface)
|
||||||
|
{
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
char * line = interface->buffer+interface->bufferPos;
|
char *line = interface->buffer + interface->bufferPos;
|
||||||
|
|
||||||
if(interface->bufferLength - interface->bufferPos > 1) {
|
if (interface->bufferLength - interface->bufferPos > 1) {
|
||||||
if(interface->buffer[interface->bufferLength-2] == '\r') {
|
if (interface->buffer[interface->bufferLength - 2] == '\r') {
|
||||||
interface->buffer[interface->bufferLength-2] = '\0';
|
interface->buffer[interface->bufferLength - 2] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(interface->commandList) {
|
if (interface->commandList) {
|
||||||
if(strcmp(line, INTERFACE_LIST_MODE_END)==0) {
|
if (strcmp(line, INTERFACE_LIST_MODE_END) == 0) {
|
||||||
DEBUG("interface %i: process command "
|
DEBUG("interface %i: process command "
|
||||||
"list\n",interface->num);
|
"list\n", interface->num);
|
||||||
ret = processListOfCommands(
|
ret = processListOfCommands(interface->fp,
|
||||||
interface->fp,
|
|
||||||
&(interface->permission),
|
&(interface->permission),
|
||||||
&(interface->expired),
|
&(interface->expired),
|
||||||
interface->commandListOK,
|
interface->commandListOK,
|
||||||
interface->commandList);
|
interface->commandList);
|
||||||
DEBUG("interface %i: process command "
|
DEBUG("interface %i: process command "
|
||||||
"list returned %i\n",
|
"list returned %i\n", interface->num, ret);
|
||||||
interface->num,
|
if (ret == 0)
|
||||||
ret);
|
commandSuccess(interface->fp);
|
||||||
if(ret==0) commandSuccess(interface->fp);
|
else if (ret == COMMAND_RETURN_CLOSE
|
||||||
else if(ret==COMMAND_RETURN_CLOSE || interface->expired)
|
|| interface->expired) {
|
||||||
{
|
|
||||||
|
|
||||||
closeInterface(interface);
|
closeInterface(interface);
|
||||||
}
|
}
|
||||||
@ -236,56 +235,48 @@ static int processLineOfInput(Interface * interface) {
|
|||||||
|
|
||||||
freeList(interface->commandList);
|
freeList(interface->commandList);
|
||||||
interface->commandList = NULL;
|
interface->commandList = NULL;
|
||||||
}
|
} else {
|
||||||
else {
|
interface->commandListSize += sizeof(ListNode);
|
||||||
interface->commandListSize+= sizeof(ListNode);
|
interface->commandListSize += strlen(line) + 1;
|
||||||
interface->commandListSize+= strlen(line)+1;
|
if (interface->commandListSize >
|
||||||
if(interface->commandListSize >
|
interface_max_command_list_size) {
|
||||||
interface_max_command_list_size)
|
|
||||||
{
|
|
||||||
ERROR("interface %i: command "
|
ERROR("interface %i: command "
|
||||||
"list size (%lli) is "
|
"list size (%lli) is "
|
||||||
"larger than the max "
|
"larger than the max "
|
||||||
"(%lli)\n",
|
"(%lli)\n",
|
||||||
interface->num,
|
interface->num,
|
||||||
(long long)interface->
|
(long long)interface->
|
||||||
commandListSize,
|
commandListSize, (long long)
|
||||||
(long long)
|
interface_max_command_list_size);
|
||||||
interface_max_command_list_size)
|
|
||||||
;
|
|
||||||
closeInterface(interface);
|
closeInterface(interface);
|
||||||
ret = COMMAND_RETURN_CLOSE;
|
ret = COMMAND_RETURN_CLOSE;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
insertInListWithoutKey(interface->commandList,
|
insertInListWithoutKey(interface->commandList,
|
||||||
strdup(line));
|
strdup(line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (strcmp(line, INTERFACE_LIST_MODE_BEGIN) == 0) {
|
||||||
if(strcmp(line, INTERFACE_LIST_MODE_BEGIN) == 0) {
|
|
||||||
interface->commandList = makeList(free, 1);
|
interface->commandList = makeList(free, 1);
|
||||||
interface->commandListSize = sizeof(List);
|
interface->commandListSize = sizeof(List);
|
||||||
interface->commandListOK = 0;
|
interface->commandListOK = 0;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
} else if (strcmp(line, INTERFACE_LIST_OK_MODE_BEGIN) == 0) {
|
||||||
else if(strcmp(line, INTERFACE_LIST_OK_MODE_BEGIN) == 0) {
|
|
||||||
interface->commandList = makeList(free, 1);
|
interface->commandList = makeList(free, 1);
|
||||||
interface->commandListSize = sizeof(List);
|
interface->commandListSize = sizeof(List);
|
||||||
interface->commandListOK = 1;
|
interface->commandListOK = 1;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
DEBUG("interface %i: process command \"%s\"\n",
|
DEBUG("interface %i: process command \"%s\"\n",
|
||||||
interface->num, line);
|
interface->num, line);
|
||||||
ret = processCommand(interface->fp,
|
ret = processCommand(interface->fp,
|
||||||
&(interface->permission),
|
&(interface->permission), line);
|
||||||
line);
|
|
||||||
DEBUG("interface %i: command returned %i\n",
|
DEBUG("interface %i: command returned %i\n",
|
||||||
interface->num, ret);
|
interface->num, ret);
|
||||||
if(ret==0) commandSuccess(interface->fp);
|
if (ret == 0)
|
||||||
else if(ret==COMMAND_RETURN_CLOSE || interface->expired)
|
commandSuccess(interface->fp);
|
||||||
{
|
else if (ret == COMMAND_RETURN_CLOSE
|
||||||
|
|| interface->expired) {
|
||||||
closeInterface(interface);
|
closeInterface(interface);
|
||||||
}
|
}
|
||||||
printInterfaceOutBuffer(interface);
|
printInterfaceOutBuffer(interface);
|
||||||
@ -295,33 +286,32 @@ static int processLineOfInput(Interface * interface) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int processBytesRead(Interface * interface, int bytesRead) {
|
static int processBytesRead(Interface * interface, int bytesRead)
|
||||||
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
while(bytesRead > 0) {
|
while (bytesRead > 0) {
|
||||||
interface->bufferLength++;
|
interface->bufferLength++;
|
||||||
bytesRead--;
|
bytesRead--;
|
||||||
if(interface->buffer[interface->bufferLength-1]=='\n') {
|
if (interface->buffer[interface->bufferLength - 1] == '\n') {
|
||||||
interface->buffer[interface->bufferLength-1] = '\0';
|
interface->buffer[interface->bufferLength - 1] = '\0';
|
||||||
ret = processLineOfInput(interface);
|
ret = processLineOfInput(interface);
|
||||||
interface->bufferPos = interface->bufferLength;
|
interface->bufferPos = interface->bufferLength;
|
||||||
}
|
}
|
||||||
if(interface->bufferLength==INTERFACE_MAX_BUFFER_LENGTH)
|
if (interface->bufferLength == INTERFACE_MAX_BUFFER_LENGTH) {
|
||||||
{
|
if (interface->bufferPos == 0) {
|
||||||
if(interface->bufferPos == 0) {
|
|
||||||
ERROR("interface %i: buffer overflow\n",
|
ERROR("interface %i: buffer overflow\n",
|
||||||
interface->num);
|
interface->num);
|
||||||
closeInterface(interface);
|
closeInterface(interface);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
interface->bufferLength-= interface->bufferPos;
|
interface->bufferLength -= interface->bufferPos;
|
||||||
memmove(interface->buffer,
|
memmove(interface->buffer,
|
||||||
interface->buffer+interface->bufferPos,
|
interface->buffer + interface->bufferPos,
|
||||||
interface->bufferLength);
|
interface->bufferLength);
|
||||||
interface->bufferPos = 0;
|
interface->bufferPos = 0;
|
||||||
}
|
}
|
||||||
if(ret == COMMAND_RETURN_KILL || ret == COMMAND_RETURN_CLOSE)
|
if (ret == COMMAND_RETURN_KILL || ret == COMMAND_RETURN_CLOSE) {
|
||||||
{
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -330,50 +320,60 @@ static int processBytesRead(Interface * interface, int bytesRead) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int interfaceReadInput(Interface * interface) {
|
static int interfaceReadInput(Interface * interface)
|
||||||
|
{
|
||||||
int bytesRead;
|
int bytesRead;
|
||||||
|
|
||||||
bytesRead = read(interface->fd,
|
bytesRead = read(interface->fd,
|
||||||
interface->buffer+interface->bufferLength,
|
interface->buffer + interface->bufferLength,
|
||||||
INTERFACE_MAX_BUFFER_LENGTH-interface->bufferLength);
|
INTERFACE_MAX_BUFFER_LENGTH - interface->bufferLength);
|
||||||
|
|
||||||
if(bytesRead > 0) return processBytesRead(interface, bytesRead);
|
if (bytesRead > 0)
|
||||||
else if(bytesRead == 0 || (bytesRead < 0 && errno != EINTR)) {
|
return processBytesRead(interface, bytesRead);
|
||||||
|
else if (bytesRead == 0 || (bytesRead < 0 && errno != EINTR)) {
|
||||||
closeInterface(interface);
|
closeInterface(interface);
|
||||||
}
|
} else
|
||||||
else return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addInterfacesReadyToReadAndListenSocketToFdSet(fd_set * fds, int * fdmax) {
|
static void addInterfacesReadyToReadAndListenSocketToFdSet(fd_set * fds,
|
||||||
|
int *fdmax)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
FD_ZERO(fds);
|
FD_ZERO(fds);
|
||||||
addListenSocketsToFdSet(fds, fdmax);
|
addListenSocketsToFdSet(fds, fdmax);
|
||||||
|
|
||||||
for(i=0;i<interface_max_connections;i++) {
|
for (i = 0; i < interface_max_connections; i++) {
|
||||||
if(interfaces[i].open && !interfaces[i].expired && !interfaces[i].bufferList) {
|
if (interfaces[i].open && !interfaces[i].expired
|
||||||
FD_SET(interfaces[i].fd,fds);
|
&& !interfaces[i].bufferList) {
|
||||||
if(*fdmax<interfaces[i].fd) *fdmax = interfaces[i].fd;
|
FD_SET(interfaces[i].fd, fds);
|
||||||
|
if (*fdmax < interfaces[i].fd)
|
||||||
|
*fdmax = interfaces[i].fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addInterfacesForBufferFlushToFdSet(fd_set * fds, int * fdmax) {
|
static void addInterfacesForBufferFlushToFdSet(fd_set * fds, int *fdmax)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
FD_ZERO(fds);
|
FD_ZERO(fds);
|
||||||
|
|
||||||
for(i=0;i<interface_max_connections;i++) {
|
for (i = 0; i < interface_max_connections; i++) {
|
||||||
if(interfaces[i].open && !interfaces[i].expired && interfaces[i].bufferList) {
|
if (interfaces[i].open && !interfaces[i].expired
|
||||||
FD_SET(interfaces[i].fd,fds);
|
&& interfaces[i].bufferList) {
|
||||||
if(*fdmax<interfaces[i].fd) *fdmax = interfaces[i].fd;
|
FD_SET(interfaces[i].fd, fds);
|
||||||
|
if (*fdmax < interfaces[i].fd)
|
||||||
|
*fdmax = interfaces[i].fd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void closeNextErroredInterface(void) {
|
static void closeNextErroredInterface(void)
|
||||||
|
{
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
int i;
|
int i;
|
||||||
@ -381,11 +381,11 @@ static void closeNextErroredInterface(void) {
|
|||||||
tv.tv_sec = 0;
|
tv.tv_sec = 0;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
for(i=0;i<interface_max_connections;i++) {
|
for (i = 0; i < interface_max_connections; i++) {
|
||||||
if(interfaces[i].open) {
|
if (interfaces[i].open) {
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(interfaces[i].fd,&fds);
|
FD_SET(interfaces[i].fd, &fds);
|
||||||
if(select(FD_SETSIZE,&fds,NULL,NULL,&tv)<0) {
|
if (select(FD_SETSIZE, &fds, NULL, NULL, &tv) < 0) {
|
||||||
closeInterface(&interfaces[i]);
|
closeInterface(&interfaces[i]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -393,7 +393,8 @@ static void closeNextErroredInterface(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int doIOForInterfaces(void) {
|
int doIOForInterfaces(void)
|
||||||
|
{
|
||||||
fd_set rfds;
|
fd_set rfds;
|
||||||
fd_set wfds;
|
fd_set wfds;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
@ -404,31 +405,35 @@ int doIOForInterfaces(void) {
|
|||||||
tv.tv_sec = 1;
|
tv.tv_sec = 1;
|
||||||
tv.tv_usec = 0;
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
fdmax = 0;
|
fdmax = 0;
|
||||||
|
|
||||||
addInterfacesReadyToReadAndListenSocketToFdSet(&rfds,&fdmax);
|
addInterfacesReadyToReadAndListenSocketToFdSet(&rfds, &fdmax);
|
||||||
addInterfacesForBufferFlushToFdSet(&wfds,&fdmax);
|
addInterfacesForBufferFlushToFdSet(&wfds, &fdmax);
|
||||||
|
|
||||||
selret = select(fdmax+1,&rfds,&wfds,NULL,&tv);
|
selret = select(fdmax + 1, &rfds, &wfds, NULL, &tv);
|
||||||
|
|
||||||
if(selret == 0 || (selret<0 && errno==EINTR)) break;
|
if (selret == 0 || (selret < 0 && errno == EINTR))
|
||||||
|
break;
|
||||||
|
|
||||||
if(selret<0) {
|
if (selret < 0) {
|
||||||
closeNextErroredInterface();
|
closeNextErroredInterface();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
getConnections(&rfds);
|
getConnections(&rfds);
|
||||||
|
|
||||||
for(i=0;i<interface_max_connections;i++) {
|
for (i = 0; i < interface_max_connections; i++) {
|
||||||
if(interfaces[i].open && FD_ISSET(interfaces[i].fd,&rfds)) {
|
if (interfaces[i].open
|
||||||
if(COMMAND_RETURN_KILL==interfaceReadInput(&(interfaces[i]))) {
|
&& FD_ISSET(interfaces[i].fd, &rfds)) {
|
||||||
|
if (COMMAND_RETURN_KILL ==
|
||||||
|
interfaceReadInput(&(interfaces[i]))) {
|
||||||
return COMMAND_RETURN_KILL;
|
return COMMAND_RETURN_KILL;
|
||||||
}
|
}
|
||||||
interfaces[i].lastTime = time(NULL);
|
interfaces[i].lastTime = time(NULL);
|
||||||
}
|
}
|
||||||
if(interfaces[i].open && FD_ISSET(interfaces[i].fd,&wfds)) {
|
if (interfaces[i].open
|
||||||
|
&& FD_ISSET(interfaces[i].fd, &wfds)) {
|
||||||
flushInterfaceBuffer(&interfaces[i]);
|
flushInterfaceBuffer(&interfaces[i]);
|
||||||
interfaces[i].lastTime = time(NULL);
|
interfaces[i].lastTime = time(NULL);
|
||||||
}
|
}
|
||||||
@ -441,16 +446,17 @@ int doIOForInterfaces(void) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initInterfaces(void) {
|
void initInterfaces(void)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
char * test;
|
char *test;
|
||||||
ConfigParam * param;
|
ConfigParam *param;
|
||||||
|
|
||||||
param = getConfigParam(CONF_CONN_TIMEOUT);
|
param = getConfigParam(CONF_CONN_TIMEOUT);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
interface_timeout = strtol(param->value,&test,10);
|
interface_timeout = strtol(param->value, &test, 10);
|
||||||
if(*test!='\0' || interface_timeout<=0) {
|
if (*test != '\0' || interface_timeout <= 0) {
|
||||||
ERROR("connection timeout \"%s\" is not a positive "
|
ERROR("connection timeout \"%s\" is not a positive "
|
||||||
"integer, line %i\n", CONF_CONN_TIMEOUT,
|
"integer, line %i\n", CONF_CONN_TIMEOUT,
|
||||||
param->line);
|
param->line);
|
||||||
@ -460,65 +466,65 @@ void initInterfaces(void) {
|
|||||||
|
|
||||||
param = getConfigParam(CONF_MAX_CONN);
|
param = getConfigParam(CONF_MAX_CONN);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
interface_max_connections = strtol(param->value, &test, 10);
|
interface_max_connections = strtol(param->value, &test, 10);
|
||||||
if(*test!='\0' || interface_max_connections<=0) {
|
if (*test != '\0' || interface_max_connections <= 0) {
|
||||||
ERROR("max connections \"%s\" is not a positive integer"
|
ERROR("max connections \"%s\" is not a positive integer"
|
||||||
", line %i\n", param->value, param->line);
|
", line %i\n", param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
} else
|
||||||
else interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT;
|
interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT;
|
||||||
|
|
||||||
param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE);
|
param = getConfigParam(CONF_MAX_COMMAND_LIST_SIZE);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
interface_max_command_list_size = strtoll(param->value,
|
interface_max_command_list_size = strtoll(param->value,
|
||||||
&test, 10);
|
&test, 10);
|
||||||
if(*test!='\0' || interface_max_command_list_size<=0) {
|
if (*test != '\0' || interface_max_command_list_size <= 0) {
|
||||||
ERROR("max command list size \"%s\" is not a positive "
|
ERROR("max command list size \"%s\" is not a positive "
|
||||||
"integer, line %i\n", param->value,
|
"integer, line %i\n", param->value, param->line);
|
||||||
param->line);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
interface_max_command_list_size*=1024;
|
interface_max_command_list_size *= 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE);
|
param = getConfigParam(CONF_MAX_OUTPUT_BUFFER_SIZE);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
interface_max_output_buffer_size = strtoll(param->value, &test,
|
interface_max_output_buffer_size = strtoll(param->value, &test,
|
||||||
10);
|
10);
|
||||||
if(*test!='\0' || interface_max_output_buffer_size<=0) {
|
if (*test != '\0' || interface_max_output_buffer_size <= 0) {
|
||||||
ERROR("max output buffer size \"%s\" is not a positive "
|
ERROR("max output buffer size \"%s\" is not a positive "
|
||||||
"integer, line %i\n", param->value,
|
"integer, line %i\n", param->value, param->line);
|
||||||
param->line);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
interface_max_output_buffer_size*=1024;
|
interface_max_output_buffer_size *= 1024;
|
||||||
}
|
}
|
||||||
|
|
||||||
interfaces = malloc(sizeof(Interface)*interface_max_connections);
|
interfaces = malloc(sizeof(Interface) * interface_max_connections);
|
||||||
|
|
||||||
for(i=0;i<interface_max_connections;i++) {
|
for (i = 0; i < interface_max_connections; i++) {
|
||||||
interfaces[i].open = 0;
|
interfaces[i].open = 0;
|
||||||
interfaces[i].num = i;
|
interfaces[i].num = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void closeAllInterfaces(void) {
|
static void closeAllInterfaces(void)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
fflush(NULL);
|
fflush(NULL);
|
||||||
|
|
||||||
for(i=0;i<interface_max_connections;i++) {
|
for (i = 0; i < interface_max_connections; i++) {
|
||||||
if(interfaces[i].open) {
|
if (interfaces[i].open) {
|
||||||
closeInterface(&(interfaces[i]));
|
closeInterface(&(interfaces[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeAllInterfaces(void) {
|
void freeAllInterfaces(void)
|
||||||
|
{
|
||||||
closeAllInterfaces();
|
closeAllInterfaces();
|
||||||
|
|
||||||
free(interfaces);
|
free(interfaces);
|
||||||
@ -526,53 +532,52 @@ void freeAllInterfaces(void) {
|
|||||||
interface_max_connections = 0;
|
interface_max_connections = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeOldInterfaces(void) {
|
void closeOldInterfaces(void)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0;i<interface_max_connections;i++) {
|
for (i = 0; i < interface_max_connections; i++) {
|
||||||
if(interfaces[i].open) {
|
if (interfaces[i].open) {
|
||||||
if(interfaces[i].expired) {
|
if (interfaces[i].expired) {
|
||||||
DEBUG("interface %i: expired\n",i);
|
DEBUG("interface %i: expired\n", i);
|
||||||
closeInterface(&(interfaces[i]));
|
closeInterface(&(interfaces[i]));
|
||||||
}
|
} else if (time(NULL) - interfaces[i].lastTime >
|
||||||
else if(time(NULL)-interfaces[i].lastTime >
|
interface_timeout) {
|
||||||
interface_timeout)
|
DEBUG("interface %i: timeout\n", i);
|
||||||
{
|
|
||||||
DEBUG("interface %i: timeout\n",i);
|
|
||||||
closeInterface(&(interfaces[i]));
|
closeInterface(&(interfaces[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flushInterfaceBuffer(Interface * interface) {
|
static void flushInterfaceBuffer(Interface * interface)
|
||||||
ListNode * node = NULL;
|
{
|
||||||
char * str;
|
ListNode *node = NULL;
|
||||||
|
char *str;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
while((node = interface->bufferList->firstNode)) {
|
while ((node = interface->bufferList->firstNode)) {
|
||||||
str = (char *)node->data;
|
str = (char *)node->data;
|
||||||
if((ret = write(interface->fd,str,strlen(str)))<0) break;
|
if ((ret = write(interface->fd, str, strlen(str))) < 0)
|
||||||
else if(ret<strlen(str)) {
|
break;
|
||||||
interface->outputBufferSize-=ret;
|
else if (ret < strlen(str)) {
|
||||||
|
interface->outputBufferSize -= ret;
|
||||||
str = strdup(&str[ret]);
|
str = strdup(&str[ret]);
|
||||||
free(node->data);
|
free(node->data);
|
||||||
node->data = str;
|
node->data = str;
|
||||||
}
|
} else {
|
||||||
else {
|
interface->outputBufferSize -= strlen(str) + 1;
|
||||||
interface->outputBufferSize-= strlen(str)+1;
|
interface->outputBufferSize -= sizeof(ListNode);
|
||||||
interface->outputBufferSize-= sizeof(ListNode);
|
deleteNodeFromList(interface->bufferList, node);
|
||||||
deleteNodeFromList(interface->bufferList,node);
|
|
||||||
}
|
}
|
||||||
interface->lastTime = time(NULL);
|
interface->lastTime = time(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!interface->bufferList->firstNode) {
|
if (!interface->bufferList->firstNode) {
|
||||||
DEBUG("interface %i: buffer empty\n",interface->num);
|
DEBUG("interface %i: buffer empty\n", interface->num);
|
||||||
freeList(interface->bufferList);
|
freeList(interface->bufferList);
|
||||||
interface->bufferList = NULL;
|
interface->bufferList = NULL;
|
||||||
}
|
} else if (ret < 0 && errno != EAGAIN && errno != EINTR) {
|
||||||
else if(ret<0 && errno!=EAGAIN && errno!=EINTR) {
|
|
||||||
/* cause interface to close */
|
/* cause interface to close */
|
||||||
DEBUG("interface %i: problems flushing buffer\n",
|
DEBUG("interface %i: problems flushing buffer\n",
|
||||||
interface->num);
|
interface->num);
|
||||||
@ -582,36 +587,38 @@ static void flushInterfaceBuffer(Interface * interface) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int interfacePrintWithFD(int fd, char * buffer, int buflen) {
|
int interfacePrintWithFD(int fd, char *buffer, int buflen)
|
||||||
|
{
|
||||||
static int i = 0;
|
static int i = 0;
|
||||||
int copylen;
|
int copylen;
|
||||||
Interface * interface;
|
Interface *interface;
|
||||||
|
|
||||||
if(i>=interface_max_connections ||
|
if (i >= interface_max_connections ||
|
||||||
!interfaces[i].open || interfaces[i].fd!=fd)
|
!interfaces[i].open || interfaces[i].fd != fd) {
|
||||||
{
|
for (i = 0; i < interface_max_connections; i++) {
|
||||||
for(i=0;i<interface_max_connections;i++) {
|
if (interfaces[i].open && interfaces[i].fd == fd)
|
||||||
if(interfaces[i].open && interfaces[i].fd==fd) break;
|
break;
|
||||||
}
|
}
|
||||||
if(i==interface_max_connections) return -1;
|
if (i == interface_max_connections)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if fd isn't found or interfaces is going to be closed, do nothing */
|
/* if fd isn't found or interfaces is going to be closed, do nothing */
|
||||||
if(interfaces[i].expired) return 0;
|
if (interfaces[i].expired)
|
||||||
|
return 0;
|
||||||
|
|
||||||
interface = interfaces+i;
|
interface = interfaces + i;
|
||||||
|
|
||||||
while(buflen>0 && !interface->expired) {
|
while (buflen > 0 && !interface->expired) {
|
||||||
copylen = buflen>
|
copylen = buflen >
|
||||||
interface->outBufSize-interface->outBuflen?
|
interface->outBufSize - interface->outBuflen ?
|
||||||
interface->outBufSize-interface->outBuflen:
|
interface->outBufSize - interface->outBuflen : buflen;
|
||||||
buflen;
|
memcpy(interface->outBuffer + interface->outBuflen, buffer,
|
||||||
memcpy(interface->outBuffer+interface->outBuflen,buffer,
|
|
||||||
copylen);
|
copylen);
|
||||||
buflen-=copylen;
|
buflen -= copylen;
|
||||||
interface->outBuflen+=copylen;
|
interface->outBuflen += copylen;
|
||||||
buffer+=copylen;
|
buffer += copylen;
|
||||||
if(interface->outBuflen>=interface->outBufSize) {
|
if (interface->outBuflen >= interface->outBufSize) {
|
||||||
printInterfaceOutBuffer(interface);
|
printInterfaceOutBuffer(interface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -619,20 +626,20 @@ int interfacePrintWithFD(int fd, char * buffer, int buflen) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printInterfaceOutBuffer(Interface * interface) {
|
static void printInterfaceOutBuffer(Interface * interface)
|
||||||
char * buffer;
|
{
|
||||||
|
char *buffer;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if(!interface->open || interface->expired || !interface->outBuflen) {
|
if (!interface->open || interface->expired || !interface->outBuflen) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(interface->bufferList) {
|
if (interface->bufferList) {
|
||||||
interface->outputBufferSize+=sizeof(ListNode);
|
interface->outputBufferSize += sizeof(ListNode);
|
||||||
interface->outputBufferSize+=interface->outBuflen+1;
|
interface->outputBufferSize += interface->outBuflen + 1;
|
||||||
if(interface->outputBufferSize>
|
if (interface->outputBufferSize >
|
||||||
interface_max_output_buffer_size)
|
interface_max_output_buffer_size) {
|
||||||
{
|
|
||||||
ERROR("interface %i: output buffer size (%lli) is "
|
ERROR("interface %i: output buffer size (%lli) is "
|
||||||
"larger than the max (%lli)\n",
|
"larger than the max (%lli)\n",
|
||||||
interface->num,
|
interface->num,
|
||||||
@ -642,51 +649,50 @@ static void printInterfaceOutBuffer(Interface * interface) {
|
|||||||
freeList(interface->bufferList);
|
freeList(interface->bufferList);
|
||||||
interface->bufferList = NULL;
|
interface->bufferList = NULL;
|
||||||
interface->expired = 1;
|
interface->expired = 1;
|
||||||
}
|
} else {
|
||||||
else {
|
buffer = malloc(interface->outBuflen + 1);
|
||||||
buffer = malloc(interface->outBuflen+1);
|
memcpy(buffer, interface->outBuffer,
|
||||||
memcpy(buffer,interface->outBuffer,interface->outBuflen);
|
interface->outBuflen);
|
||||||
buffer[interface->outBuflen] = '\0';
|
buffer[interface->outBuflen] = '\0';
|
||||||
insertInListWithoutKey(interface->bufferList,(void *)buffer);
|
insertInListWithoutKey(interface->bufferList,
|
||||||
|
(void *)buffer);
|
||||||
flushInterfaceBuffer(interface);
|
flushInterfaceBuffer(interface);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if ((ret = write(interface->fd, interface->outBuffer,
|
||||||
if((ret = write(interface->fd,interface->outBuffer,
|
interface->outBuflen)) < 0) {
|
||||||
interface->outBuflen))<0)
|
if (errno == EAGAIN || errno == EINTR) {
|
||||||
{
|
buffer = malloc(interface->outBuflen + 1);
|
||||||
if(errno==EAGAIN || errno==EINTR) {
|
memcpy(buffer, interface->outBuffer,
|
||||||
buffer = malloc(interface->outBuflen+1);
|
|
||||||
memcpy(buffer,interface->outBuffer,
|
|
||||||
interface->outBuflen);
|
interface->outBuflen);
|
||||||
buffer[interface->outBuflen] = '\0';
|
buffer[interface->outBuflen] = '\0';
|
||||||
interface->bufferList = makeList(free, 1);
|
interface->bufferList = makeList(free, 1);
|
||||||
insertInListWithoutKey(interface->bufferList,
|
insertInListWithoutKey(interface->bufferList,
|
||||||
(void *)buffer);
|
(void *)buffer);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
DEBUG("interface %i: problems writing\n",
|
DEBUG("interface %i: problems writing\n",
|
||||||
interface->num);
|
interface->num);
|
||||||
interface->expired = 1;
|
interface->expired = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
} else if (ret < interface->outBuflen) {
|
||||||
else if(ret<interface->outBuflen) {
|
buffer = malloc(interface->outBuflen - ret + 1);
|
||||||
buffer = malloc(interface->outBuflen-ret+1);
|
memcpy(buffer, interface->outBuffer + ret,
|
||||||
memcpy(buffer,interface->outBuffer+ret,
|
interface->outBuflen - ret);
|
||||||
interface->outBuflen-ret);
|
buffer[interface->outBuflen - ret] = '\0';
|
||||||
buffer[interface->outBuflen-ret] = '\0';
|
|
||||||
interface->bufferList = makeList(free, 1);
|
interface->bufferList = makeList(free, 1);
|
||||||
insertInListWithoutKey(interface->bufferList,buffer);
|
insertInListWithoutKey(interface->bufferList, buffer);
|
||||||
}
|
}
|
||||||
/* if we needed to create buffer, initialize bufferSize info */
|
/* if we needed to create buffer, initialize bufferSize info */
|
||||||
if(interface->bufferList) {
|
if (interface->bufferList) {
|
||||||
DEBUG("interface %i: buffer created\n",interface->num);
|
DEBUG("interface %i: buffer created\n", interface->num);
|
||||||
interface->outputBufferSize = sizeof(List);
|
interface->outputBufferSize = sizeof(List);
|
||||||
interface->outputBufferSize+=sizeof(ListNode);
|
interface->outputBufferSize += sizeof(ListNode);
|
||||||
interface->outputBufferSize+=strlen(
|
interface->outputBufferSize += strlen((char *)
|
||||||
(char *)interface->bufferList->
|
interface->
|
||||||
firstNode->data)+1;
|
bufferList->
|
||||||
|
firstNode->data) +
|
||||||
|
1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +27,10 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
void initInterfaces();
|
void initInterfaces();
|
||||||
void openAInterface(int fd, struct sockaddr * addr);
|
void openAInterface(int fd, struct sockaddr *addr);
|
||||||
void freeAllInterfaces();
|
void freeAllInterfaces();
|
||||||
void closeOldInterfaces();
|
void closeOldInterfaces();
|
||||||
int interfacePrintWithFD(int fd, char * buffer, int len);
|
int interfacePrintWithFD(int fd, char *buffer, int len);
|
||||||
|
|
||||||
int doIOForInterfaces();
|
int doIOForInterfaces();
|
||||||
|
|
||||||
|
414
src/list.c
414
src/list.c
@ -16,7 +16,6 @@
|
|||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -25,31 +24,36 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
static void makeListNodesArray(List * list) {
|
static void makeListNodesArray(List * list)
|
||||||
ListNode * node = list->firstNode;
|
{
|
||||||
|
ListNode *node = list->firstNode;
|
||||||
long i;
|
long i;
|
||||||
|
|
||||||
if(!list->numberOfNodes) return;
|
if (!list->numberOfNodes)
|
||||||
|
return;
|
||||||
|
|
||||||
list->nodesArray = realloc(list->nodesArray,
|
list->nodesArray = realloc(list->nodesArray,
|
||||||
sizeof(ListNode *)*list->numberOfNodes);
|
sizeof(ListNode *) * list->numberOfNodes);
|
||||||
|
|
||||||
for(i=0;i<list->numberOfNodes;i++) {
|
for (i = 0; i < list->numberOfNodes; i++) {
|
||||||
list->nodesArray[i] = node;
|
list->nodesArray[i] = node;
|
||||||
node = node->nextNode;
|
node = node->nextNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeListNodesArray(List * list) {
|
static void freeListNodesArray(List * list)
|
||||||
if(!list->nodesArray) return;
|
{
|
||||||
|
if (!list->nodesArray)
|
||||||
|
return;
|
||||||
free(list->nodesArray);
|
free(list->nodesArray);
|
||||||
list->nodesArray = NULL;
|
list->nodesArray = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
List * makeList(ListFreeDataFunc * freeDataFunc, int strdupKeys) {
|
List *makeList(ListFreeDataFunc * freeDataFunc, int strdupKeys)
|
||||||
List * list = malloc(sizeof(List));
|
{
|
||||||
|
List *list = malloc(sizeof(List));
|
||||||
|
|
||||||
assert(list!=NULL);
|
assert(list != NULL);
|
||||||
|
|
||||||
list->sorted = 0;
|
list->sorted = 0;
|
||||||
list->firstNode = NULL;
|
list->firstNode = NULL;
|
||||||
@ -62,61 +66,63 @@ List * makeList(ListFreeDataFunc * freeDataFunc, int strdupKeys) {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListNode * insertInListBeforeNode(List * list, ListNode * beforeNode, int pos, char * key, void * data)
|
ListNode *insertInListBeforeNode(List * list, ListNode * beforeNode, int pos,
|
||||||
|
char *key, void *data)
|
||||||
{
|
{
|
||||||
ListNode * node;
|
ListNode *node;
|
||||||
|
|
||||||
assert(list!=NULL);
|
assert(list != NULL);
|
||||||
assert(key!=NULL);
|
assert(key != NULL);
|
||||||
/*assert(data!=NULL);*/
|
/*assert(data!=NULL); */
|
||||||
|
|
||||||
node = malloc(sizeof(ListNode));
|
node = malloc(sizeof(ListNode));
|
||||||
assert(node!=NULL);
|
assert(node != NULL);
|
||||||
|
|
||||||
node->nextNode = beforeNode;
|
node->nextNode = beforeNode;
|
||||||
if(beforeNode==list->firstNode) {
|
if (beforeNode == list->firstNode) {
|
||||||
if(list->firstNode==NULL) {
|
if (list->firstNode == NULL) {
|
||||||
assert(list->lastNode==NULL);
|
assert(list->lastNode == NULL);
|
||||||
list->lastNode = node;
|
list->lastNode = node;
|
||||||
}
|
} else {
|
||||||
else {
|
assert(list->lastNode != NULL);
|
||||||
assert(list->lastNode!=NULL);
|
assert(list->lastNode->nextNode == NULL);
|
||||||
assert(list->lastNode->nextNode==NULL);
|
|
||||||
list->firstNode->prevNode = node;
|
list->firstNode->prevNode = node;
|
||||||
}
|
}
|
||||||
node->prevNode = NULL;
|
node->prevNode = NULL;
|
||||||
list->firstNode = node;
|
list->firstNode = node;
|
||||||
}
|
} else {
|
||||||
else {
|
if (beforeNode) {
|
||||||
if(beforeNode) {
|
|
||||||
node->prevNode = beforeNode->prevNode;
|
node->prevNode = beforeNode->prevNode;
|
||||||
beforeNode->prevNode = node;
|
beforeNode->prevNode = node;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
node->prevNode = list->lastNode;
|
node->prevNode = list->lastNode;
|
||||||
list->lastNode = node;
|
list->lastNode = node;
|
||||||
}
|
}
|
||||||
node->prevNode->nextNode = node;
|
node->prevNode->nextNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(list->strdupKeys) node->key = strdup(key);
|
if (list->strdupKeys)
|
||||||
else node->key = key;
|
node->key = strdup(key);
|
||||||
|
else
|
||||||
|
node->key = key;
|
||||||
|
|
||||||
node->data = data;
|
node->data = data;
|
||||||
|
|
||||||
list->numberOfNodes++;
|
list->numberOfNodes++;
|
||||||
|
|
||||||
if(list->sorted) {
|
if (list->sorted) {
|
||||||
list->nodesArray = realloc(list->nodesArray,
|
list->nodesArray = realloc(list->nodesArray,
|
||||||
list->numberOfNodes*sizeof(ListNode *));
|
list->numberOfNodes *
|
||||||
if(node == list->lastNode) {
|
sizeof(ListNode *));
|
||||||
list->nodesArray[list->numberOfNodes-1] = node;
|
if (node == list->lastNode) {
|
||||||
}
|
list->nodesArray[list->numberOfNodes - 1] = node;
|
||||||
else if(pos < 0) makeListNodesArray(list);
|
} else if (pos < 0)
|
||||||
|
makeListNodesArray(list);
|
||||||
else {
|
else {
|
||||||
memmove(list->nodesArray+pos+1, list->nodesArray+pos,
|
memmove(list->nodesArray + pos + 1,
|
||||||
sizeof(ListNode *)*
|
list->nodesArray + pos,
|
||||||
(list->numberOfNodes-pos-1));
|
sizeof(ListNode *) * (list->numberOfNodes -
|
||||||
|
pos - 1));
|
||||||
list->nodesArray[pos] = node;
|
list->nodesArray[pos] = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -124,30 +130,33 @@ ListNode * insertInListBeforeNode(List * list, ListNode * beforeNode, int po
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListNode * insertInList(List * list, char * key, void * data) {
|
ListNode *insertInList(List * list, char *key, void *data)
|
||||||
ListNode * node;
|
{
|
||||||
|
ListNode *node;
|
||||||
|
|
||||||
assert(list!=NULL);
|
assert(list != NULL);
|
||||||
assert(key!=NULL);
|
assert(key != NULL);
|
||||||
/*assert(data!=NULL);*/
|
/*assert(data!=NULL); */
|
||||||
|
|
||||||
node = malloc(sizeof(ListNode));
|
node = malloc(sizeof(ListNode));
|
||||||
assert(node!=NULL);
|
assert(node != NULL);
|
||||||
|
|
||||||
if(list->nodesArray) freeListNodesArray(list);
|
if (list->nodesArray)
|
||||||
|
freeListNodesArray(list);
|
||||||
|
|
||||||
if(list->firstNode==NULL) {
|
if (list->firstNode == NULL) {
|
||||||
assert(list->lastNode==NULL);
|
assert(list->lastNode == NULL);
|
||||||
list->firstNode = node;
|
list->firstNode = node;
|
||||||
}
|
} else {
|
||||||
else {
|
assert(list->lastNode != NULL);
|
||||||
assert(list->lastNode!=NULL);
|
assert(list->lastNode->nextNode == NULL);
|
||||||
assert(list->lastNode->nextNode==NULL);
|
|
||||||
list->lastNode->nextNode = node;
|
list->lastNode->nextNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(list->strdupKeys) node->key = strdup(key);
|
if (list->strdupKeys)
|
||||||
else node->key = key;
|
node->key = strdup(key);
|
||||||
|
else
|
||||||
|
node->key = key;
|
||||||
|
|
||||||
node->data = data;
|
node->data = data;
|
||||||
node->nextNode = NULL;
|
node->nextNode = NULL;
|
||||||
@ -160,24 +169,25 @@ ListNode * insertInList(List * list, char * key, void * data) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
int insertInListWithoutKey(List * list, void * data) {
|
int insertInListWithoutKey(List * list, void *data)
|
||||||
ListNode * node;
|
{
|
||||||
|
ListNode *node;
|
||||||
|
|
||||||
assert(list!=NULL);
|
assert(list != NULL);
|
||||||
assert(data!=NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
node = malloc(sizeof(ListNode));
|
node = malloc(sizeof(ListNode));
|
||||||
assert(node!=NULL);
|
assert(node != NULL);
|
||||||
|
|
||||||
if(list->nodesArray) freeListNodesArray(list);
|
if (list->nodesArray)
|
||||||
|
freeListNodesArray(list);
|
||||||
|
|
||||||
if(list->firstNode==NULL) {
|
if (list->firstNode == NULL) {
|
||||||
assert(list->lastNode==NULL);
|
assert(list->lastNode == NULL);
|
||||||
list->firstNode = node;
|
list->firstNode = node;
|
||||||
}
|
} else {
|
||||||
else {
|
assert(list->lastNode != NULL);
|
||||||
assert(list->lastNode!=NULL);
|
assert(list->lastNode->nextNode == NULL);
|
||||||
assert(list->lastNode->nextNode==NULL);
|
|
||||||
list->lastNode->nextNode = node;
|
list->lastNode->nextNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,147 +205,157 @@ int insertInListWithoutKey(List * list, void * data) {
|
|||||||
|
|
||||||
/* if _key_ is not found, *_node_ is assigned to the node before which
|
/* if _key_ is not found, *_node_ is assigned to the node before which
|
||||||
the info would be found */
|
the info would be found */
|
||||||
int findNodeInList(List * list, char * key, ListNode ** node, int * pos) {
|
int findNodeInList(List * list, char *key, ListNode ** node, int *pos)
|
||||||
|
{
|
||||||
long high;
|
long high;
|
||||||
long low;
|
long low;
|
||||||
long cur;
|
long cur;
|
||||||
ListNode * tmpNode;
|
ListNode *tmpNode;
|
||||||
int cmp;
|
int cmp;
|
||||||
|
|
||||||
assert(list!=NULL);
|
assert(list != NULL);
|
||||||
|
|
||||||
if(list->sorted && list->nodesArray) {
|
if (list->sorted && list->nodesArray) {
|
||||||
high = list->numberOfNodes-1;
|
high = list->numberOfNodes - 1;
|
||||||
low = 0;
|
low = 0;
|
||||||
cur = high;
|
cur = high;
|
||||||
|
|
||||||
while(high>low) {
|
while (high > low) {
|
||||||
cur = (high+low)/2;
|
cur = (high + low) / 2;
|
||||||
tmpNode = list->nodesArray[cur];
|
tmpNode = list->nodesArray[cur];
|
||||||
cmp = strcmp(tmpNode->key,key);
|
cmp = strcmp(tmpNode->key, key);
|
||||||
if(cmp==0) {
|
if (cmp == 0) {
|
||||||
*node = tmpNode;
|
*node = tmpNode;
|
||||||
*pos = cur;
|
*pos = cur;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else if (cmp > 0)
|
||||||
else if(cmp>0) high = cur;
|
high = cur;
|
||||||
else {
|
else {
|
||||||
if(low==cur) break;
|
if (low == cur)
|
||||||
|
break;
|
||||||
low = cur;
|
low = cur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cur = high;
|
cur = high;
|
||||||
if(cur>=0) {
|
if (cur >= 0) {
|
||||||
tmpNode = list->nodesArray[cur];
|
tmpNode = list->nodesArray[cur];
|
||||||
*node = tmpNode;
|
*node = tmpNode;
|
||||||
*pos = high;
|
*pos = high;
|
||||||
cmp = tmpNode ? strcmp(tmpNode->key,key) : -1;
|
cmp = tmpNode ? strcmp(tmpNode->key, key) : -1;
|
||||||
if( 0 == cmp ) return 1;
|
if (0 == cmp)
|
||||||
else if( cmp > 0) return 0;
|
return 1;
|
||||||
|
else if (cmp > 0)
|
||||||
|
return 0;
|
||||||
else {
|
else {
|
||||||
*pos = -1;
|
*pos = -1;
|
||||||
*node = NULL;
|
*node = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
*pos = 0;
|
*pos = 0;
|
||||||
*node = list->firstNode;
|
*node = list->firstNode;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tmpNode = list->firstNode;
|
tmpNode = list->firstNode;
|
||||||
|
|
||||||
while(tmpNode!=NULL && strcmp(tmpNode->key,key)!=0) {
|
while (tmpNode != NULL && strcmp(tmpNode->key, key) != 0) {
|
||||||
tmpNode = tmpNode->nextNode;
|
tmpNode = tmpNode->nextNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
*node = tmpNode;
|
*node = tmpNode;
|
||||||
if(tmpNode) return 1;
|
if (tmpNode)
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int findInList(List * list, char * key, void ** data) {
|
|
||||||
ListNode * node;
|
|
||||||
int pos;
|
|
||||||
|
|
||||||
if(findNodeInList(list, key, &node, &pos)) {
|
|
||||||
if(data) *data = node->data;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int deleteFromList(List * list,char * key) {
|
int findInList(List * list, char *key, void **data)
|
||||||
ListNode * tmpNode;
|
{
|
||||||
|
ListNode *node;
|
||||||
|
int pos;
|
||||||
|
|
||||||
assert(list!=NULL);
|
if (findNodeInList(list, key, &node, &pos)) {
|
||||||
|
if (data)
|
||||||
|
*data = node->data;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deleteFromList(List * list, char *key)
|
||||||
|
{
|
||||||
|
ListNode *tmpNode;
|
||||||
|
|
||||||
|
assert(list != NULL);
|
||||||
|
|
||||||
tmpNode = list->firstNode;
|
tmpNode = list->firstNode;
|
||||||
|
|
||||||
while(tmpNode!=NULL && strcmp(tmpNode->key,key)!=0) {
|
while (tmpNode != NULL && strcmp(tmpNode->key, key) != 0) {
|
||||||
tmpNode = tmpNode->nextNode;
|
tmpNode = tmpNode->nextNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tmpNode!=NULL)
|
if (tmpNode != NULL)
|
||||||
deleteNodeFromList(list,tmpNode);
|
deleteNodeFromList(list, tmpNode);
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteNodeFromList(List * list,ListNode * node) {
|
void deleteNodeFromList(List * list, ListNode * node)
|
||||||
assert(list!=NULL);
|
{
|
||||||
assert(node!=NULL);
|
assert(list != NULL);
|
||||||
|
assert(node != NULL);
|
||||||
|
|
||||||
if(node->prevNode==NULL) {
|
if (node->prevNode == NULL) {
|
||||||
list->firstNode = node->nextNode;
|
list->firstNode = node->nextNode;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
node->prevNode->nextNode = node->nextNode;
|
node->prevNode->nextNode = node->nextNode;
|
||||||
}
|
}
|
||||||
if(node->nextNode==NULL) {
|
if (node->nextNode == NULL) {
|
||||||
list->lastNode = node->prevNode;
|
list->lastNode = node->prevNode;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
node->nextNode->prevNode = node->prevNode;
|
node->nextNode->prevNode = node->prevNode;
|
||||||
}
|
}
|
||||||
if(list->freeDataFunc) {
|
if (list->freeDataFunc) {
|
||||||
list->freeDataFunc(node->data);
|
list->freeDataFunc(node->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(list->strdupKeys) free(node->key);
|
if (list->strdupKeys)
|
||||||
|
free(node->key);
|
||||||
free(node);
|
free(node);
|
||||||
list->numberOfNodes--;
|
list->numberOfNodes--;
|
||||||
|
|
||||||
if(list->nodesArray) {
|
if (list->nodesArray) {
|
||||||
freeListNodesArray(list);
|
freeListNodesArray(list);
|
||||||
if(list->sorted) makeListNodesArray(list);
|
if (list->sorted)
|
||||||
|
makeListNodesArray(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeList(void * list) {
|
void freeList(void *list)
|
||||||
ListNode * tmpNode;
|
{
|
||||||
ListNode * tmpNode2;
|
ListNode *tmpNode;
|
||||||
|
ListNode *tmpNode2;
|
||||||
|
|
||||||
assert(list!=NULL);
|
assert(list != NULL);
|
||||||
|
|
||||||
tmpNode = ((List *)list)->firstNode;
|
tmpNode = ((List *) list)->firstNode;
|
||||||
|
|
||||||
if(((List *)list)->nodesArray) free(((List *)list)->nodesArray);
|
if (((List *) list)->nodesArray)
|
||||||
|
free(((List *) list)->nodesArray);
|
||||||
|
|
||||||
while(tmpNode!=NULL) {
|
while (tmpNode != NULL) {
|
||||||
tmpNode2 = tmpNode->nextNode;
|
tmpNode2 = tmpNode->nextNode;
|
||||||
if(((List *)list)->strdupKeys) free(tmpNode->key);
|
if (((List *) list)->strdupKeys)
|
||||||
if(((List *)list)->freeDataFunc) {
|
free(tmpNode->key);
|
||||||
((List *)list)->freeDataFunc(tmpNode->data);
|
if (((List *) list)->freeDataFunc) {
|
||||||
|
((List *) list)->freeDataFunc(tmpNode->data);
|
||||||
}
|
}
|
||||||
free(tmpNode);
|
free(tmpNode);
|
||||||
tmpNode = tmpNode2;
|
tmpNode = tmpNode2;
|
||||||
@ -344,12 +364,13 @@ void freeList(void * list) {
|
|||||||
free(list);
|
free(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void swapNodes(ListNode * nodeA, ListNode * nodeB) {
|
static void swapNodes(ListNode * nodeA, ListNode * nodeB)
|
||||||
char * key;
|
{
|
||||||
void * data;
|
char *key;
|
||||||
|
void *data;
|
||||||
|
|
||||||
assert(nodeA!=NULL);
|
assert(nodeA != NULL);
|
||||||
assert(nodeB!=NULL);
|
assert(nodeB != NULL);
|
||||||
|
|
||||||
key = nodeB->key;
|
key = nodeB->key;
|
||||||
data = nodeB->data;
|
data = nodeB->data;
|
||||||
@ -361,98 +382,116 @@ static void swapNodes(ListNode * nodeA, ListNode * nodeB) {
|
|||||||
nodeA->data = data;
|
nodeA->data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bubbleSort(ListNode ** nodesArray, long start, long end) {
|
static void bubbleSort(ListNode ** nodesArray, long start, long end)
|
||||||
|
{
|
||||||
long i;
|
long i;
|
||||||
long j;
|
long j;
|
||||||
ListNode * node;
|
ListNode *node;
|
||||||
|
|
||||||
if(start>=end) return;
|
if (start >= end)
|
||||||
|
return;
|
||||||
|
|
||||||
for(j=start;j<end;j++) {
|
for (j = start; j < end; j++) {
|
||||||
for(i=end-1;i>=start;i--) {
|
for (i = end - 1; i >= start; i--) {
|
||||||
node = nodesArray[i];
|
node = nodesArray[i];
|
||||||
if(strcmp(node->key,node->nextNode->key)>0) {
|
if (strcmp(node->key, node->nextNode->key) > 0) {
|
||||||
swapNodes(node,node->nextNode);
|
swapNodes(node, node->nextNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quickSort(ListNode ** nodesArray, long start, long end) {
|
static void quickSort(ListNode ** nodesArray, long start, long end)
|
||||||
if(start>=end) return;
|
{
|
||||||
else if(end-start<5) bubbleSort(nodesArray,start,end);
|
if (start >= end)
|
||||||
|
return;
|
||||||
|
else if (end - start < 5)
|
||||||
|
bubbleSort(nodesArray, start, end);
|
||||||
else {
|
else {
|
||||||
long i;
|
long i;
|
||||||
ListNode * node;
|
ListNode *node;
|
||||||
long pivot;
|
long pivot;
|
||||||
ListNode * pivotNode;
|
ListNode *pivotNode;
|
||||||
char * pivotKey;
|
char *pivotKey;
|
||||||
|
|
||||||
List * startList = makeList(free, 0);
|
List *startList = makeList(free, 0);
|
||||||
List * endList = makeList(free, 0);
|
List *endList = makeList(free, 0);
|
||||||
long * startPtr = malloc(sizeof(long));
|
long *startPtr = malloc(sizeof(long));
|
||||||
long * endPtr = malloc(sizeof(long));
|
long *endPtr = malloc(sizeof(long));
|
||||||
*startPtr = start;
|
*startPtr = start;
|
||||||
*endPtr = end;
|
*endPtr = end;
|
||||||
insertInListWithoutKey(startList,(void *)startPtr);
|
insertInListWithoutKey(startList, (void *)startPtr);
|
||||||
insertInListWithoutKey(endList,(void *)endPtr);
|
insertInListWithoutKey(endList, (void *)endPtr);
|
||||||
|
|
||||||
while(startList->numberOfNodes) {
|
while (startList->numberOfNodes) {
|
||||||
start = *((long *)startList->lastNode->data);
|
start = *((long *)startList->lastNode->data);
|
||||||
end = *((long *)endList->lastNode->data);
|
end = *((long *)endList->lastNode->data);
|
||||||
|
|
||||||
if(end-start<5) {
|
if (end - start < 5) {
|
||||||
bubbleSort(nodesArray,start,end);
|
bubbleSort(nodesArray, start, end);
|
||||||
deleteNodeFromList(startList,startList->lastNode);
|
deleteNodeFromList(startList,
|
||||||
deleteNodeFromList(endList,endList->lastNode);
|
startList->lastNode);
|
||||||
}
|
deleteNodeFromList(endList, endList->lastNode);
|
||||||
else {
|
} else {
|
||||||
pivot = (start+end)/2;
|
pivot = (start + end) / 2;
|
||||||
pivotNode = nodesArray[pivot];
|
pivotNode = nodesArray[pivot];
|
||||||
pivotKey = pivotNode->key;
|
pivotKey = pivotNode->key;
|
||||||
|
|
||||||
for(i=pivot-1;i>=start;i--) {
|
for (i = pivot - 1; i >= start; i--) {
|
||||||
node = nodesArray[i];
|
node = nodesArray[i];
|
||||||
if(strcmp(node->key,pivotKey)>0) {
|
if (strcmp(node->key, pivotKey) > 0) {
|
||||||
pivot--;
|
pivot--;
|
||||||
if(pivot>i) {
|
if (pivot > i) {
|
||||||
swapNodes(node,nodesArray[pivot]);
|
swapNodes(node,
|
||||||
|
nodesArray
|
||||||
|
[pivot]);
|
||||||
}
|
}
|
||||||
swapNodes(pivotNode,nodesArray[pivot]);
|
swapNodes(pivotNode,
|
||||||
|
nodesArray[pivot]);
|
||||||
pivotNode = nodesArray[pivot];
|
pivotNode = nodesArray[pivot];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(i=pivot+1;i<=end;i++) {
|
for (i = pivot + 1; i <= end; i++) {
|
||||||
node = nodesArray[i];
|
node = nodesArray[i];
|
||||||
if(strcmp(pivotKey,node->key)>0) {
|
if (strcmp(pivotKey, node->key) > 0) {
|
||||||
pivot++;
|
pivot++;
|
||||||
if(pivot<i) {
|
if (pivot < i) {
|
||||||
swapNodes(node,nodesArray[pivot]);
|
swapNodes(node,
|
||||||
|
nodesArray
|
||||||
|
[pivot]);
|
||||||
}
|
}
|
||||||
swapNodes(pivotNode,nodesArray[pivot]);
|
swapNodes(pivotNode,
|
||||||
|
nodesArray[pivot]);
|
||||||
pivotNode = nodesArray[pivot];
|
pivotNode = nodesArray[pivot];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteNodeFromList(startList,startList->lastNode);
|
deleteNodeFromList(startList,
|
||||||
deleteNodeFromList(endList,endList->lastNode);
|
startList->lastNode);
|
||||||
|
deleteNodeFromList(endList, endList->lastNode);
|
||||||
|
|
||||||
if(pivot-1-start>0) {
|
if (pivot - 1 - start > 0) {
|
||||||
startPtr = malloc(sizeof(long));
|
startPtr = malloc(sizeof(long));
|
||||||
endPtr = malloc(sizeof(long));
|
endPtr = malloc(sizeof(long));
|
||||||
*startPtr = start;
|
*startPtr = start;
|
||||||
*endPtr = pivot-1;
|
*endPtr = pivot - 1;
|
||||||
insertInListWithoutKey(startList,(void *)startPtr);
|
insertInListWithoutKey(startList,
|
||||||
insertInListWithoutKey(endList,(void *)endPtr);
|
(void *)
|
||||||
|
startPtr);
|
||||||
|
insertInListWithoutKey(endList,
|
||||||
|
(void *)endPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(end-pivot-1>0) {
|
if (end - pivot - 1 > 0) {
|
||||||
startPtr = malloc(sizeof(long));
|
startPtr = malloc(sizeof(long));
|
||||||
endPtr = malloc(sizeof(long));
|
endPtr = malloc(sizeof(long));
|
||||||
*startPtr = pivot+1;
|
*startPtr = pivot + 1;
|
||||||
*endPtr = end;
|
*endPtr = end;
|
||||||
insertInListWithoutKey(startList,(void *)startPtr);
|
insertInListWithoutKey(startList,
|
||||||
insertInListWithoutKey(endList,(void *)endPtr);
|
(void *)
|
||||||
|
startPtr);
|
||||||
|
insertInListWithoutKey(endList,
|
||||||
|
(void *)endPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -462,15 +501,18 @@ static void quickSort(ListNode ** nodesArray, long start, long end) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sortList(List * list) {
|
void sortList(List * list)
|
||||||
assert(list!=NULL);
|
{
|
||||||
|
assert(list != NULL);
|
||||||
|
|
||||||
list->sorted = 1;
|
list->sorted = 1;
|
||||||
|
|
||||||
if(list->numberOfNodes<2) return;
|
if (list->numberOfNodes < 2)
|
||||||
|
return;
|
||||||
|
|
||||||
if(list->nodesArray) freeListNodesArray(list);
|
if (list->nodesArray)
|
||||||
|
freeListNodesArray(list);
|
||||||
makeListNodesArray(list);
|
makeListNodesArray(list);
|
||||||
|
|
||||||
quickSort(list->nodesArray,0,list->numberOfNodes-1);
|
quickSort(list->nodesArray, 0, list->numberOfNodes - 1);
|
||||||
}
|
}
|
||||||
|
37
src/list.h
37
src/list.h
@ -16,7 +16,6 @@
|
|||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef LIST_H
|
#ifndef LIST_H
|
||||||
#define LIST_H
|
#define LIST_H
|
||||||
|
|
||||||
@ -32,26 +31,26 @@ typedef void ListFreeDataFunc(void *);
|
|||||||
|
|
||||||
typedef struct _ListNode {
|
typedef struct _ListNode {
|
||||||
/* used to identify node (ie. when using findInList) */
|
/* used to identify node (ie. when using findInList) */
|
||||||
char * key;
|
char *key;
|
||||||
/* data store in node */
|
/* data store in node */
|
||||||
void * data;
|
void *data;
|
||||||
/* next node in list */
|
/* next node in list */
|
||||||
struct _ListNode * nextNode;
|
struct _ListNode *nextNode;
|
||||||
/* previous node in list */
|
/* previous node in list */
|
||||||
struct _ListNode * prevNode;
|
struct _ListNode *prevNode;
|
||||||
} ListNode;
|
} ListNode;
|
||||||
|
|
||||||
typedef struct _List {
|
typedef struct _List {
|
||||||
/* first node in list */
|
/* first node in list */
|
||||||
ListNode * firstNode;
|
ListNode *firstNode;
|
||||||
/* last node in list */
|
/* last node in list */
|
||||||
ListNode * lastNode;
|
ListNode *lastNode;
|
||||||
/* function used to free data stored in nodes of the list */
|
/* function used to free data stored in nodes of the list */
|
||||||
ListFreeDataFunc * freeDataFunc;
|
ListFreeDataFunc *freeDataFunc;
|
||||||
/* number of nodes */
|
/* number of nodes */
|
||||||
long numberOfNodes;
|
long numberOfNodes;
|
||||||
/* array for searching when list is sorted */
|
/* array for searching when list is sorted */
|
||||||
ListNode ** nodesArray;
|
ListNode **nodesArray;
|
||||||
/* sorted */
|
/* sorted */
|
||||||
int sorted;
|
int sorted;
|
||||||
/* weather to strdup() key's on insertion */
|
/* weather to strdup() key's on insertion */
|
||||||
@ -63,7 +62,7 @@ typedef struct _List {
|
|||||||
* DEFAULT_FREE_DATAFUNC to use free()
|
* DEFAULT_FREE_DATAFUNC to use free()
|
||||||
* returns pointer to new list if successful, NULL otherwise
|
* returns pointer to new list if successful, NULL otherwise
|
||||||
*/
|
*/
|
||||||
List * makeList(ListFreeDataFunc * freeDataFunc, int strdupKeys);
|
List *makeList(ListFreeDataFunc * freeDataFunc, int strdupKeys);
|
||||||
|
|
||||||
/* inserts a node into _list_ with _key_ and _data_
|
/* inserts a node into _list_ with _key_ and _data_
|
||||||
* _list_ -> list the data will be inserted in
|
* _list_ -> list the data will be inserted in
|
||||||
@ -71,21 +70,21 @@ List * makeList(ListFreeDataFunc * freeDataFunc, int strdupKeys);
|
|||||||
* _data_ -> data to be inserted in list
|
* _data_ -> data to be inserted in list
|
||||||
* returns 1 if successful, 0 otherwise
|
* returns 1 if successful, 0 otherwise
|
||||||
*/
|
*/
|
||||||
ListNode * insertInList(List * list,char * key,void * data);
|
ListNode *insertInList(List * list, char *key, void *data);
|
||||||
|
|
||||||
ListNode * insertInListBeforeNode(List * list, ListNode * beforeNode,
|
ListNode *insertInListBeforeNode(List * list, ListNode * beforeNode,
|
||||||
int pos, char * key, void * data);
|
int pos, char *key, void *data);
|
||||||
|
|
||||||
int insertInListWithoutKey(List * list,void * data);
|
int insertInListWithoutKey(List * list, void *data);
|
||||||
|
|
||||||
/* deletes the first node in the list with the key _key_
|
/* deletes the first node in the list with the key _key_
|
||||||
* _list_ -> list the node will be deleted from
|
* _list_ -> list the node will be deleted from
|
||||||
* _key_ -> key used to identify node to delete
|
* _key_ -> key used to identify node to delete
|
||||||
* returns 1 if node is found and deleted, 0 otherwise
|
* returns 1 if node is found and deleted, 0 otherwise
|
||||||
*/
|
*/
|
||||||
int deleteFromList(List * list,char * key);
|
int deleteFromList(List * list, char *key);
|
||||||
|
|
||||||
void deleteNodeFromList(List * list,ListNode * node);
|
void deleteNodeFromList(List * list, ListNode * node);
|
||||||
|
|
||||||
/* finds data in a list based on key
|
/* finds data in a list based on key
|
||||||
* _list_ -> list to search for _key_ in
|
* _list_ -> list to search for _key_ in
|
||||||
@ -95,16 +94,16 @@ void deleteNodeFromList(List * list,ListNode * node);
|
|||||||
* _data_ can be NULL
|
* _data_ can be NULL
|
||||||
* returns 1 if successful, 0 otherwise
|
* returns 1 if successful, 0 otherwise
|
||||||
*/
|
*/
|
||||||
int findInList(List * list, char * key, void ** data);
|
int findInList(List * list, char *key, void **data);
|
||||||
|
|
||||||
/* if _key_ is not found, *_node_ is assigned to the node before which
|
/* if _key_ is not found, *_node_ is assigned to the node before which
|
||||||
the info would be found */
|
the info would be found */
|
||||||
int findNodeInList(List * list, char * key, ListNode ** node, int * pos);
|
int findNodeInList(List * list, char *key, ListNode ** node, int *pos);
|
||||||
|
|
||||||
/* frees memory malloc'd for list and its nodes
|
/* frees memory malloc'd for list and its nodes
|
||||||
* _list_ -> List to be free'd
|
* _list_ -> List to be free'd
|
||||||
*/
|
*/
|
||||||
void freeList(void * list);
|
void freeList(void *list);
|
||||||
|
|
||||||
void sortList(List * list);
|
void sortList(List * list);
|
||||||
|
|
||||||
|
115
src/listen.c
115
src/listen.c
@ -40,18 +40,17 @@
|
|||||||
|
|
||||||
#define DEFAULT_PORT 6600
|
#define DEFAULT_PORT 6600
|
||||||
|
|
||||||
int * listenSockets = NULL;
|
int *listenSockets = NULL;
|
||||||
int numberOfListenSockets = 0;
|
int numberOfListenSockets = 0;
|
||||||
|
|
||||||
static void establishListen(unsigned int port,
|
static void establishListen(unsigned int port,
|
||||||
struct sockaddr * addrp,
|
struct sockaddr *addrp, socklen_t addrlen)
|
||||||
socklen_t addrlen)
|
|
||||||
{
|
{
|
||||||
int pf;
|
int pf;
|
||||||
int sock;
|
int sock;
|
||||||
int allowReuse = ALLOW_REUSE;
|
int allowReuse = ALLOW_REUSE;
|
||||||
|
|
||||||
switch(addrp->sa_family) {
|
switch (addrp->sa_family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
pf = PF_INET;
|
pf = PF_INET;
|
||||||
break;
|
break;
|
||||||
@ -64,49 +63,49 @@ static void establishListen(unsigned int port,
|
|||||||
pf = PF_UNIX;
|
pf = PF_UNIX;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERROR("unknown address family: %i\n",addrp->sa_family);
|
ERROR("unknown address family: %i\n", addrp->sa_family);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((sock = socket(pf,SOCK_STREAM,0)) < 0) {
|
if ((sock = socket(pf, SOCK_STREAM, 0)) < 0) {
|
||||||
ERROR("socket < 0\n");
|
ERROR("socket < 0\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fcntl(sock, F_SETFL ,fcntl(sock, F_GETFL) | O_NONBLOCK) < 0) {
|
if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) < 0) {
|
||||||
ERROR("problems setting nonblocking on listen socket: %s\n",
|
ERROR("problems setting nonblocking on listen socket: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&allowReuse,
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&allowReuse,
|
||||||
sizeof(allowReuse))<0)
|
sizeof(allowReuse)) < 0) {
|
||||||
{
|
|
||||||
ERROR("problems setsockopt'ing: %s\n", strerror(errno));
|
ERROR("problems setsockopt'ing: %s\n", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bind(sock,addrp,addrlen)<0) {
|
if (bind(sock, addrp, addrlen) < 0) {
|
||||||
ERROR("unable to bind port %u", port);
|
ERROR("unable to bind port %u", port);
|
||||||
ERROR(": %s\n", strerror(errno));
|
ERROR(": %s\n", strerror(errno));
|
||||||
ERROR("maybe MPD is still running?\n");
|
ERROR("maybe MPD is still running?\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(listen(sock,5)<0) {
|
if (listen(sock, 5) < 0) {
|
||||||
ERROR("problems listen'ing: %s\n", strerror(errno));
|
ERROR("problems listen'ing: %s\n", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfListenSockets++;
|
numberOfListenSockets++;
|
||||||
listenSockets =
|
listenSockets =
|
||||||
realloc(listenSockets,sizeof(int)*numberOfListenSockets);
|
realloc(listenSockets, sizeof(int) * numberOfListenSockets);
|
||||||
|
|
||||||
listenSockets[numberOfListenSockets-1] = sock;
|
listenSockets[numberOfListenSockets - 1] = sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parseListenConfigParam(unsigned int port, ConfigParam * param) {
|
static void parseListenConfigParam(unsigned int port, ConfigParam * param)
|
||||||
struct sockaddr * addrp;
|
{
|
||||||
|
struct sockaddr *addrp;
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
struct sockaddr_in sin;
|
struct sockaddr_in sin;
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
@ -120,54 +119,52 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param) {
|
|||||||
sin.sin_port = htons(port);
|
sin.sin_port = htons(port);
|
||||||
sin.sin_family = AF_INET;
|
sin.sin_family = AF_INET;
|
||||||
|
|
||||||
if(!param || 0==strcmp(param->value, "any")) {
|
if (!param || 0 == strcmp(param->value, "any")) {
|
||||||
DEBUG("binding to any address\n");
|
DEBUG("binding to any address\n");
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if(ipv6Supported()) {
|
if (ipv6Supported()) {
|
||||||
sin6.sin6_addr = in6addr_any;
|
sin6.sin6_addr = in6addr_any;
|
||||||
addrp = (struct sockaddr *) &sin6;
|
addrp = (struct sockaddr *)&sin6;
|
||||||
addrlen = sizeof(struct sockaddr_in6);
|
addrlen = sizeof(struct sockaddr_in6);
|
||||||
establishListen(port, addrp, addrlen);
|
establishListen(port, addrp, addrlen);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sin.sin_addr.s_addr = INADDR_ANY;
|
sin.sin_addr.s_addr = INADDR_ANY;
|
||||||
addrp = (struct sockaddr *) &sin;
|
addrp = (struct sockaddr *)&sin;
|
||||||
addrlen = sizeof(struct sockaddr_in);
|
addrlen = sizeof(struct sockaddr_in);
|
||||||
establishListen(port, addrp, addrlen);
|
establishListen(port, addrp, addrlen);
|
||||||
}
|
} else {
|
||||||
else {
|
struct hostent *he;
|
||||||
struct hostent * he;
|
|
||||||
DEBUG("binding to address for %s\n", param->value);
|
DEBUG("binding to address for %s\n", param->value);
|
||||||
if(!(he = gethostbyname(param->value))) {
|
if (!(he = gethostbyname(param->value))) {
|
||||||
ERROR("can't lookup host \"%s\" at line %i\n",
|
ERROR("can't lookup host \"%s\" at line %i\n",
|
||||||
param->value, param->line);
|
param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
switch(he->h_addrtype) {
|
switch (he->h_addrtype) {
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
if(!ipv6Supported()) {
|
if (!ipv6Supported()) {
|
||||||
ERROR("no IPv6 support, but a IPv6 address "
|
ERROR("no IPv6 support, but a IPv6 address "
|
||||||
"found for \"%s\" at line %i\n",
|
"found for \"%s\" at line %i\n",
|
||||||
param->value, param->line);
|
param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
bcopy((char *)he->h_addr,(char *)
|
bcopy((char *)he->h_addr, (char *)
|
||||||
&sin6.sin6_addr.s6_addr,he->h_length);
|
&sin6.sin6_addr.s6_addr, he->h_length);
|
||||||
addrp = (struct sockaddr *) &sin6;
|
addrp = (struct sockaddr *)&sin6;
|
||||||
addrlen = sizeof(struct sockaddr_in6);
|
addrlen = sizeof(struct sockaddr_in6);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
bcopy((char *)he->h_addr,(char *)&sin.sin_addr.s_addr,
|
bcopy((char *)he->h_addr, (char *)&sin.sin_addr.s_addr,
|
||||||
he->h_length);
|
he->h_length);
|
||||||
addrp = (struct sockaddr *) &sin;
|
addrp = (struct sockaddr *)&sin;
|
||||||
addrlen = sizeof(struct sockaddr_in);
|
addrlen = sizeof(struct sockaddr_in);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERROR("address type for \"%s\" is not IPv4 or IPv6 "
|
ERROR("address type for \"%s\" is not IPv4 or IPv6 "
|
||||||
"at line %i\n",
|
"at line %i\n", param->value, param->line);
|
||||||
param->value, param->line);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,21 +172,21 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void listenOnPort(void) {
|
void listenOnPort(void)
|
||||||
|
{
|
||||||
int port = DEFAULT_PORT;
|
int port = DEFAULT_PORT;
|
||||||
ConfigParam * param = getNextConfigParam(CONF_BIND_TO_ADDRESS,NULL);
|
ConfigParam *param = getNextConfigParam(CONF_BIND_TO_ADDRESS, NULL);
|
||||||
|
|
||||||
{
|
{
|
||||||
ConfigParam * portParam = getConfigParam(CONF_PORT);
|
ConfigParam *portParam = getConfigParam(CONF_PORT);
|
||||||
|
|
||||||
if(portParam) {
|
if (portParam) {
|
||||||
char * test;
|
char *test;
|
||||||
port = strtol(portParam->value, &test, 10);
|
port = strtol(portParam->value, &test, 10);
|
||||||
if(port <= 0 || *test != '\0') {
|
if (port <= 0 || *test != '\0') {
|
||||||
ERROR("%s \"%s\" specified at line %i is not a "
|
ERROR("%s \"%s\" specified at line %i is not a "
|
||||||
"positive integer", CONF_PORT,
|
"positive integer", CONF_PORT,
|
||||||
portParam->value,
|
portParam->value, portParam->line);
|
||||||
portParam->line);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,47 +197,51 @@ void listenOnPort(void) {
|
|||||||
} while ((param = getNextConfigParam(CONF_BIND_TO_ADDRESS, param)));
|
} while ((param = getNextConfigParam(CONF_BIND_TO_ADDRESS, param)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void addListenSocketsToFdSet(fd_set * fds, int * fdmax) {
|
void addListenSocketsToFdSet(fd_set * fds, int *fdmax)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0; i<numberOfListenSockets; i++) {
|
for (i = 0; i < numberOfListenSockets; i++) {
|
||||||
FD_SET(listenSockets[i], fds);
|
FD_SET(listenSockets[i], fds);
|
||||||
if(listenSockets[i] > *fdmax) *fdmax = listenSockets[i];
|
if (listenSockets[i] > *fdmax)
|
||||||
|
*fdmax = listenSockets[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeAllListenSockets(void) {
|
void closeAllListenSockets(void)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
DEBUG("closeAllListenSockets called\n");
|
DEBUG("closeAllListenSockets called\n");
|
||||||
|
|
||||||
for(i=0; i<numberOfListenSockets; i++) {
|
for (i = 0; i < numberOfListenSockets; i++) {
|
||||||
DEBUG("closing listen socket %i\n", i);
|
DEBUG("closing listen socket %i\n", i);
|
||||||
while(close(listenSockets[i]) < 0 && errno==EINTR);
|
while (close(listenSockets[i]) < 0 && errno == EINTR) ;
|
||||||
}
|
}
|
||||||
freeAllListenSockets();
|
freeAllListenSockets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeAllListenSockets(void) {
|
void freeAllListenSockets(void)
|
||||||
|
{
|
||||||
numberOfListenSockets = 0;
|
numberOfListenSockets = 0;
|
||||||
free(listenSockets);
|
free(listenSockets);
|
||||||
listenSockets = NULL;
|
listenSockets = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getConnections(fd_set * fds) {
|
void getConnections(fd_set * fds)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
int fd = 0;
|
int fd = 0;
|
||||||
struct sockaddr sockAddr;
|
struct sockaddr sockAddr;
|
||||||
socklen_t socklen = sizeof(sockAddr);
|
socklen_t socklen = sizeof(sockAddr);
|
||||||
|
|
||||||
for(i=0; i<numberOfListenSockets; i++) {
|
for (i = 0; i < numberOfListenSockets; i++) {
|
||||||
if(FD_ISSET(listenSockets[i], fds)) {
|
if (FD_ISSET(listenSockets[i], fds)) {
|
||||||
if((fd = accept(listenSockets[i], &sockAddr, &socklen))
|
if ((fd = accept(listenSockets[i], &sockAddr, &socklen))
|
||||||
>= 0)
|
>= 0) {
|
||||||
{
|
openAInterface(fd, &sockAddr);
|
||||||
openAInterface(fd,&sockAddr);
|
} else if (fd < 0
|
||||||
}
|
&& (errno != EAGAIN && errno != EINTR)) {
|
||||||
else if(fd<0 && (errno!=EAGAIN && errno!=EINTR)) {
|
|
||||||
ERROR("Problems accept()'ing\n");
|
ERROR("Problems accept()'ing\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,6 @@ void closeAllListenSockets();
|
|||||||
void freeAllListenSockets();
|
void freeAllListenSockets();
|
||||||
|
|
||||||
/* fdmax should be initialized to something */
|
/* fdmax should be initialized to something */
|
||||||
void addListenSocketsToFdSet(fd_set * fds, int * fdmax);
|
void addListenSocketsToFdSet(fd_set * fds, int *fdmax);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
47
src/log.c
47
src/log.c
@ -29,23 +29,25 @@
|
|||||||
int logLevel = LOG_LEVEL_LOW;
|
int logLevel = LOG_LEVEL_LOW;
|
||||||
short warningFlushed = 0;
|
short warningFlushed = 0;
|
||||||
|
|
||||||
static char * warningBuffer = NULL;
|
static char *warningBuffer = NULL;
|
||||||
|
|
||||||
void initLog(void) {
|
void initLog(void)
|
||||||
ConfigParam * param = getConfigParam(CONF_LOG_LEVEL);
|
{
|
||||||
|
ConfigParam *param = getConfigParam(CONF_LOG_LEVEL);
|
||||||
|
|
||||||
if(!param) return;
|
if (!param)
|
||||||
|
return;
|
||||||
|
|
||||||
if(0 == strcmp(param->value, "default")) {
|
if (0 == strcmp(param->value, "default")) {
|
||||||
if(logLevel<LOG_LEVEL_LOW) logLevel = LOG_LEVEL_LOW;
|
if (logLevel < LOG_LEVEL_LOW)
|
||||||
}
|
logLevel = LOG_LEVEL_LOW;
|
||||||
else if(0 == strcmp(param->value, "secure")) {
|
} else if (0 == strcmp(param->value, "secure")) {
|
||||||
if(logLevel<LOG_LEVEL_SECURE) logLevel = LOG_LEVEL_SECURE;
|
if (logLevel < LOG_LEVEL_SECURE)
|
||||||
}
|
logLevel = LOG_LEVEL_SECURE;
|
||||||
else if(0 == strcmp(param->value, "verbose")) {
|
} else if (0 == strcmp(param->value, "verbose")) {
|
||||||
if(logLevel<LOG_LEVEL_DEBUG) logLevel = LOG_LEVEL_DEBUG;
|
if (logLevel < LOG_LEVEL_DEBUG)
|
||||||
}
|
logLevel = LOG_LEVEL_DEBUG;
|
||||||
else {
|
} else {
|
||||||
ERROR("unknown log level \"%s\" at line %i\n",
|
ERROR("unknown log level \"%s\" at line %i\n",
|
||||||
param->value, param->line);
|
param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -54,11 +56,12 @@ void initLog(void) {
|
|||||||
|
|
||||||
#define BUFFER_LENGTH 4096
|
#define BUFFER_LENGTH 4096
|
||||||
|
|
||||||
void bufferWarning(char * format, ... ) {
|
void bufferWarning(char *format, ...)
|
||||||
|
{
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
char temp[BUFFER_LENGTH+1];
|
char temp[BUFFER_LENGTH + 1];
|
||||||
|
|
||||||
memset(temp, 0, BUFFER_LENGTH+1);
|
memset(temp, 0, BUFFER_LENGTH + 1);
|
||||||
|
|
||||||
va_start(arglist, format);
|
va_start(arglist, format);
|
||||||
|
|
||||||
@ -69,15 +72,17 @@ void bufferWarning(char * format, ... ) {
|
|||||||
va_end(arglist);
|
va_end(arglist);
|
||||||
}
|
}
|
||||||
|
|
||||||
void flushWarningLog(void) {
|
void flushWarningLog(void)
|
||||||
char * s;
|
{
|
||||||
|
char *s;
|
||||||
|
|
||||||
DEBUG("flushing warning messages\n");
|
DEBUG("flushing warning messages\n");
|
||||||
|
|
||||||
if(warningBuffer == NULL) return;
|
if (warningBuffer == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
s = strtok(warningBuffer, "\n");
|
s = strtok(warningBuffer, "\n");
|
||||||
while ( s != NULL ) {
|
while (s != NULL) {
|
||||||
myfprintf(stderr, "%s\n", s);
|
myfprintf(stderr, "%s\n", s);
|
||||||
|
|
||||||
s = strtok(NULL, "\n");
|
s = strtok(NULL, "\n");
|
||||||
|
@ -37,7 +37,6 @@ extern short warningFlushed;
|
|||||||
#define SECURE(...) if(logLevel>=LOG_LEVEL_SECURE) \
|
#define SECURE(...) if(logLevel>=LOG_LEVEL_SECURE) \
|
||||||
myfprintf(stdout, __VA_ARGS__)
|
myfprintf(stdout, __VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
#define DEBUG(...) if(logLevel>=LOG_LEVEL_DEBUG) \
|
#define DEBUG(...) if(logLevel>=LOG_LEVEL_DEBUG) \
|
||||||
myfprintf(stdout, __VA_ARGS__)
|
myfprintf(stdout, __VA_ARGS__)
|
||||||
|
|
||||||
@ -48,7 +47,7 @@ extern short warningFlushed;
|
|||||||
|
|
||||||
void initLog();
|
void initLog();
|
||||||
|
|
||||||
void bufferWarning(char * format, ... );
|
void bufferWarning(char *format, ...);
|
||||||
|
|
||||||
void flushWarningLog();
|
void flushWarningLog();
|
||||||
|
|
||||||
|
203
src/ls.c
203
src/ls.c
@ -27,33 +27,34 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
static char * remoteUrlPrefixes[] =
|
static char *remoteUrlPrefixes[] = {
|
||||||
{
|
|
||||||
"http://",
|
"http://",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
int printRemoteUrlHandlers(FILE * fp) {
|
int printRemoteUrlHandlers(FILE * fp)
|
||||||
char ** prefixes = remoteUrlPrefixes;
|
{
|
||||||
|
char **prefixes = remoteUrlPrefixes;
|
||||||
|
|
||||||
while (*prefixes) {
|
while (*prefixes) {
|
||||||
myfprintf(fp,"handler: %s\n", *prefixes);
|
myfprintf(fp, "handler: %s\n", *prefixes);
|
||||||
prefixes++;
|
prefixes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isValidRemoteUtf8Url(char * utf8url) {
|
int isValidRemoteUtf8Url(char *utf8url)
|
||||||
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
char * temp;
|
char *temp;
|
||||||
|
|
||||||
switch(isRemoteUrl(utf8url)) {
|
switch (isRemoteUrl(utf8url)) {
|
||||||
case 1:
|
case 1:
|
||||||
ret = 1;
|
ret = 1;
|
||||||
temp = utf8url;
|
temp = utf8url;
|
||||||
while(*temp) {
|
while (*temp) {
|
||||||
if((*temp >= 'a' && *temp <= 'z') ||
|
if ((*temp >= 'a' && *temp <= 'z') ||
|
||||||
(*temp >= 'A' && *temp <= 'Z') ||
|
(*temp >= 'A' && *temp <= 'Z') ||
|
||||||
(*temp >= '0' && *temp <= '9') ||
|
(*temp >= '0' && *temp <= '9') ||
|
||||||
*temp == '$' ||
|
*temp == '$' ||
|
||||||
@ -70,12 +71,8 @@ int isValidRemoteUtf8Url(char * utf8url) {
|
|||||||
*temp == '/' ||
|
*temp == '/' ||
|
||||||
*temp == ':' ||
|
*temp == ':' ||
|
||||||
*temp == '?' ||
|
*temp == '?' ||
|
||||||
*temp == ';' ||
|
*temp == ';' || *temp == '&' || *temp == '=') {
|
||||||
*temp == '&' ||
|
} else {
|
||||||
*temp == '=')
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ret = 1;
|
ret = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -87,13 +84,14 @@ int isValidRemoteUtf8Url(char * utf8url) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isRemoteUrl(char * url) {
|
int isRemoteUrl(char *url)
|
||||||
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
char ** urlPrefixes = remoteUrlPrefixes;
|
char **urlPrefixes = remoteUrlPrefixes;
|
||||||
|
|
||||||
while(*urlPrefixes) {
|
while (*urlPrefixes) {
|
||||||
count++;
|
count++;
|
||||||
if(strncmp(*urlPrefixes,url,strlen(*urlPrefixes)) == 0) {
|
if (strncmp(*urlPrefixes, url, strlen(*urlPrefixes)) == 0) {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
urlPrefixes++;
|
urlPrefixes++;
|
||||||
@ -102,46 +100,47 @@ int isRemoteUrl(char * url) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lsPlaylists(FILE * fp, char * utf8path) {
|
int lsPlaylists(FILE * fp, char *utf8path)
|
||||||
DIR * dir;
|
{
|
||||||
|
DIR *dir;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct dirent * ent;
|
struct dirent *ent;
|
||||||
char * dup;
|
char *dup;
|
||||||
char * utf8;
|
char *utf8;
|
||||||
char s[MAXPATHLEN+1];
|
char s[MAXPATHLEN + 1];
|
||||||
List * list = NULL;
|
List *list = NULL;
|
||||||
ListNode * node = NULL;
|
ListNode *node = NULL;
|
||||||
char * path = utf8ToFsCharset(utf8path);
|
char *path = utf8ToFsCharset(utf8path);
|
||||||
char * actualPath = rpp2app(path);
|
char *actualPath = rpp2app(path);
|
||||||
int actlen = strlen(actualPath)+1;
|
int actlen = strlen(actualPath) + 1;
|
||||||
int maxlen = MAXPATHLEN-actlen;
|
int maxlen = MAXPATHLEN - actlen;
|
||||||
int suflen = strlen(PLAYLIST_FILE_SUFFIX)+1;
|
int suflen = strlen(PLAYLIST_FILE_SUFFIX) + 1;
|
||||||
int suff;
|
int suff;
|
||||||
|
|
||||||
if(actlen>MAXPATHLEN-1 || (dir = opendir(actualPath))==NULL) {
|
if (actlen > MAXPATHLEN - 1 || (dir = opendir(actualPath)) == NULL) {
|
||||||
free(path);
|
free(path);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
s[MAXPATHLEN] = '\0';
|
s[MAXPATHLEN] = '\0';
|
||||||
/* this is safe, notice actlen > MAXPATHLEN-1 above */
|
/* this is safe, notice actlen > MAXPATHLEN-1 above */
|
||||||
strcpy(s,actualPath);
|
strcpy(s, actualPath);
|
||||||
strcat(s,"/");
|
strcat(s, "/");
|
||||||
|
|
||||||
while((ent = readdir(dir))) {
|
while ((ent = readdir(dir))) {
|
||||||
dup = ent->d_name;
|
dup = ent->d_name;
|
||||||
if(dup[0]!='.' &&
|
if (dup[0] != '.' &&
|
||||||
(suff=strlen(dup)-suflen)>0 &&
|
(suff = strlen(dup) - suflen) > 0 &&
|
||||||
dup[suff]=='.' &&
|
dup[suff] == '.' &&
|
||||||
strcmp(dup+suff+1,PLAYLIST_FILE_SUFFIX)==0)
|
strcmp(dup + suff + 1, PLAYLIST_FILE_SUFFIX) == 0) {
|
||||||
{
|
strncpy(s + actlen, ent->d_name, maxlen);
|
||||||
strncpy(s+actlen,ent->d_name,maxlen);
|
if (stat(s, &st) == 0) {
|
||||||
if(stat(s,&st)==0) {
|
if (S_ISREG(st.st_mode)) {
|
||||||
if(S_ISREG(st.st_mode)) {
|
if (list == NULL)
|
||||||
if(list==NULL) list = makeList(NULL, 1);
|
list = makeList(NULL, 1);
|
||||||
dup[suff] = '\0';
|
dup[suff] = '\0';
|
||||||
if((utf8 = fsCharsetToUtf8(dup))) {
|
if ((utf8 = fsCharsetToUtf8(dup))) {
|
||||||
insertInList(list,utf8,NULL);
|
insertInList(list, utf8, NULL);
|
||||||
free(utf8);
|
free(utf8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,21 +151,23 @@ int lsPlaylists(FILE * fp, char * utf8path) {
|
|||||||
closedir(dir);
|
closedir(dir);
|
||||||
free(path);
|
free(path);
|
||||||
|
|
||||||
if(list) {
|
if (list) {
|
||||||
int i;
|
int i;
|
||||||
sortList(list);
|
sortList(list);
|
||||||
|
|
||||||
dup = malloc(strlen(utf8path)+2);
|
dup = malloc(strlen(utf8path) + 2);
|
||||||
strcpy(dup,utf8path);
|
strcpy(dup, utf8path);
|
||||||
for(i = strlen(dup)-1; i >= 0 && dup[i]=='/'; i--) {
|
for (i = strlen(dup) - 1; i >= 0 && dup[i] == '/'; i--) {
|
||||||
dup[i] = '\0';
|
dup[i] = '\0';
|
||||||
}
|
}
|
||||||
if(strlen(dup)) strcat(dup,"/");
|
if (strlen(dup))
|
||||||
|
strcat(dup, "/");
|
||||||
|
|
||||||
node = list->firstNode;
|
node = list->firstNode;
|
||||||
while(node!=NULL) {
|
while (node != NULL) {
|
||||||
if(!strchr(node->key, '\n')) {
|
if (!strchr(node->key, '\n')) {
|
||||||
myfprintf(fp,"playlist: %s%s\n",dup,node->key);
|
myfprintf(fp, "playlist: %s%s\n", dup,
|
||||||
|
node->key);
|
||||||
}
|
}
|
||||||
node = node->nextNode;
|
node = node->nextNode;
|
||||||
}
|
}
|
||||||
@ -178,71 +179,79 @@ int lsPlaylists(FILE * fp, char * utf8path) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int myStat(char * utf8file, struct stat * st) {
|
int myStat(char *utf8file, struct stat *st)
|
||||||
char * file = utf8ToFsCharset(utf8file);
|
{
|
||||||
char * actualFile = file;
|
char *file = utf8ToFsCharset(utf8file);
|
||||||
|
char *actualFile = file;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if(actualFile[0]!='/') actualFile = rmp2amp(file);
|
if (actualFile[0] != '/')
|
||||||
|
actualFile = rmp2amp(file);
|
||||||
|
|
||||||
ret = stat(actualFile,st);
|
ret = stat(actualFile, st);
|
||||||
|
|
||||||
free(file);
|
free(file);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int isFile(char * utf8file, time_t * mtime) {
|
static int isFile(char *utf8file, time_t * mtime)
|
||||||
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if(myStat(utf8file,&st)==0) {
|
if (myStat(utf8file, &st) == 0) {
|
||||||
if(S_ISREG(st.st_mode)) {
|
if (S_ISREG(st.st_mode)) {
|
||||||
if(mtime) *mtime = st.st_mtime;
|
if (mtime)
|
||||||
|
*mtime = st.st_mtime;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else {
|
||||||
else
|
DEBUG("isFile: %s is not a regular file\n", utf8file);
|
||||||
{
|
|
||||||
DEBUG("isFile: %s is not a regular file\n",utf8file);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
DEBUG("isFile: failed to stat: %s: %s\n", utf8file,
|
||||||
DEBUG("isFile: failed to stat: %s: %s\n", utf8file, strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* suffixes should be ascii only characters */
|
/* suffixes should be ascii only characters */
|
||||||
char * getSuffix(char * utf8file) {
|
char *getSuffix(char *utf8file)
|
||||||
char * ret = NULL;
|
{
|
||||||
|
char *ret = NULL;
|
||||||
|
|
||||||
while(*utf8file) {
|
while (*utf8file) {
|
||||||
if(*utf8file == '.') ret = utf8file+1;
|
if (*utf8file == '.')
|
||||||
|
ret = utf8file + 1;
|
||||||
utf8file++;
|
utf8file++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hasSuffix(char * utf8file, char * suffix) {
|
int hasSuffix(char *utf8file, char *suffix)
|
||||||
char * s = getSuffix(utf8file);
|
{
|
||||||
if(s && 0==strcmp(s,suffix)) return 1;
|
char *s = getSuffix(utf8file);
|
||||||
|
if (s && 0 == strcmp(s, suffix))
|
||||||
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isPlaylist(char * utf8file) {
|
int isPlaylist(char *utf8file)
|
||||||
if(isFile(utf8file,NULL)) {
|
{
|
||||||
return hasSuffix(utf8file,PLAYLIST_FILE_SUFFIX);
|
if (isFile(utf8file, NULL)) {
|
||||||
|
return hasSuffix(utf8file, PLAYLIST_FILE_SUFFIX);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int isDir(char * utf8name) {
|
int isDir(char *utf8name)
|
||||||
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if(myStat(utf8name,&st)==0) {
|
if (myStat(utf8name, &st) == 0) {
|
||||||
if(S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,26 +259,28 @@ int isDir(char * utf8name) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputPlugin * hasMusicSuffix(char * utf8file, unsigned int next) {
|
InputPlugin *hasMusicSuffix(char *utf8file, unsigned int next)
|
||||||
InputPlugin * ret = NULL;
|
{
|
||||||
|
InputPlugin *ret = NULL;
|
||||||
|
|
||||||
char * s = getSuffix(utf8file);
|
char *s = getSuffix(utf8file);
|
||||||
if(s) {
|
if (s) {
|
||||||
ret = getInputPluginFromSuffix(s, next);
|
ret = getInputPluginFromSuffix(s, next);
|
||||||
}
|
} else {
|
||||||
else {
|
DEBUG("hasMusicSuffix: The file: %s has no valid suffix\n",
|
||||||
DEBUG("hasMusicSuffix: The file: %s has no valid suffix\n",utf8file);
|
utf8file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputPlugin * isMusic(char * utf8file, time_t * mtime, unsigned int next) {
|
InputPlugin *isMusic(char *utf8file, time_t * mtime, unsigned int next)
|
||||||
if(isFile(utf8file,mtime)) {
|
{
|
||||||
InputPlugin * plugin = hasMusicSuffix(utf8file, next);
|
if (isFile(utf8file, mtime)) {
|
||||||
|
InputPlugin *plugin = hasMusicSuffix(utf8file, next);
|
||||||
if (plugin != NULL)
|
if (plugin != NULL)
|
||||||
return plugin;
|
return plugin;
|
||||||
}
|
}
|
||||||
DEBUG("isMusic: %s is not a valid file\n",utf8file);
|
DEBUG("isMusic: %s is not a valid file\n", utf8file);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
18
src/ls.h
18
src/ls.h
@ -29,23 +29,23 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
int lsPlaylists(FILE * fp, char * utf8path);
|
int lsPlaylists(FILE * fp, char *utf8path);
|
||||||
|
|
||||||
char * getSuffix(char * utf8file);
|
char *getSuffix(char *utf8file);
|
||||||
|
|
||||||
int isValidRemoteUtf8Url(char * utf8url);
|
int isValidRemoteUtf8Url(char *utf8url);
|
||||||
|
|
||||||
int isRemoteUrl(char * url);
|
int isRemoteUrl(char *url);
|
||||||
|
|
||||||
int myStat(char * utf8file, struct stat * st);
|
int myStat(char *utf8file, struct stat *st);
|
||||||
|
|
||||||
int isDir(char * utf8name);
|
int isDir(char *utf8name);
|
||||||
|
|
||||||
int isPlaylist(char * utf8file);
|
int isPlaylist(char *utf8file);
|
||||||
|
|
||||||
InputPlugin * hasMusicSuffix(char * utf8file, unsigned int next);
|
InputPlugin *hasMusicSuffix(char *utf8file, unsigned int next);
|
||||||
|
|
||||||
InputPlugin * isMusic(char * utf8file, time_t * mtime, unsigned int next);
|
InputPlugin *isMusic(char *utf8file, time_t * mtime, unsigned int next);
|
||||||
|
|
||||||
int printRemoteUrlHandlers(FILE * fp);
|
int printRemoteUrlHandlers(FILE * fp);
|
||||||
|
|
||||||
|
@ -20,7 +20,8 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void initMetadataChunk(MetadataChunk * chunk) {
|
static void initMetadataChunk(MetadataChunk * chunk)
|
||||||
|
{
|
||||||
memset(chunk, 0, sizeof(MetadataChunk));
|
memset(chunk, 0, sizeof(MetadataChunk));
|
||||||
|
|
||||||
chunk->name = -1;
|
chunk->name = -1;
|
||||||
@ -35,10 +36,11 @@ static void initMetadataChunk(MetadataChunk * chunk) {
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
MpdTag * metadataChunkToMpdTagDup(MetadataChunk * chunk) {
|
MpdTag *metadataChunkToMpdTagDup(MetadataChunk * chunk)
|
||||||
MpdTag * ret = newMpdTag();
|
{
|
||||||
|
MpdTag *ret = newMpdTag();
|
||||||
|
|
||||||
chunk->buffer[METADATA_BUFFER_LENGTH-1] = '\0';
|
chunk->buffer[METADATA_BUFFER_LENGTH - 1] = '\0';
|
||||||
|
|
||||||
dupElementToTag(TAG_ITEM_NAME, chunk->name);
|
dupElementToTag(TAG_ITEM_NAME, chunk->name);
|
||||||
dupElementToTag(TAG_ITEM_TITLE, chunk->title);
|
dupElementToTag(TAG_ITEM_TITLE, chunk->title);
|
||||||
@ -59,17 +61,19 @@ MpdTag * metadataChunkToMpdTagDup(MetadataChunk * chunk) {
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyMpdTagToMetadataChunk(MpdTag * tag, MetadataChunk * chunk) {
|
void copyMpdTagToMetadataChunk(MpdTag * tag, MetadataChunk * chunk)
|
||||||
|
{
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
int slen;
|
int slen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
initMetadataChunk(chunk);
|
initMetadataChunk(chunk);
|
||||||
|
|
||||||
if(!tag) return;
|
if (!tag)
|
||||||
|
return;
|
||||||
|
|
||||||
for(i = 0; i < tag->numOfItems; i++) {
|
for (i = 0; i < tag->numOfItems; i++) {
|
||||||
switch(tag->items[i].type) {
|
switch (tag->items[i].type) {
|
||||||
case TAG_ITEM_NAME:
|
case TAG_ITEM_NAME:
|
||||||
copyStringToChunk(tag->items[i].value, chunk->name);
|
copyStringToChunk(tag->items[i].value, chunk->name);
|
||||||
break;
|
break;
|
||||||
|
@ -31,7 +31,7 @@ typedef struct _MetadataChunk {
|
|||||||
char buffer[METADATA_BUFFER_LENGTH];
|
char buffer[METADATA_BUFFER_LENGTH];
|
||||||
} MetadataChunk;
|
} MetadataChunk;
|
||||||
|
|
||||||
MpdTag * metadataChunkToMpdTagDup(MetadataChunk * chunk);
|
MpdTag *metadataChunkToMpdTagDup(MetadataChunk * chunk);
|
||||||
|
|
||||||
void copyMpdTagToMetadataChunk(MpdTag * tag, MetadataChunk * chunk);
|
void copyMpdTagToMetadataChunk(MpdTag * tag, MetadataChunk * chunk);
|
||||||
|
|
||||||
|
107
src/myfprintf.c
107
src/myfprintf.c
@ -33,19 +33,21 @@
|
|||||||
#define BUFFER_LENGTH MAXPATHLEN+1024
|
#define BUFFER_LENGTH MAXPATHLEN+1024
|
||||||
|
|
||||||
static int myfprintf_stdLogMode = 0;
|
static int myfprintf_stdLogMode = 0;
|
||||||
static FILE * myfprintf_out;
|
static FILE *myfprintf_out;
|
||||||
static FILE * myfprintf_err;
|
static FILE *myfprintf_err;
|
||||||
static char * myfprintf_outFilename;
|
static char *myfprintf_outFilename;
|
||||||
static char * myfprintf_errFilename;
|
static char *myfprintf_errFilename;
|
||||||
|
|
||||||
static void blockingWrite(int fd, char * string, int len) {
|
static void blockingWrite(int fd, char *string, int len)
|
||||||
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
while(len) {
|
while (len) {
|
||||||
ret = write(fd,string,len);
|
ret = write(fd, string, len);
|
||||||
if(ret==0) return;
|
if (ret == 0)
|
||||||
if(ret<0) {
|
return;
|
||||||
switch(errno) {
|
if (ret < 0) {
|
||||||
|
switch (errno) {
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
case EINTR:
|
case EINTR:
|
||||||
continue;
|
continue;
|
||||||
@ -53,12 +55,13 @@ static void blockingWrite(int fd, char * string, int len) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
len-= ret;
|
len -= ret;
|
||||||
string+= ret;
|
string += ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void myfprintfStdLogMode(FILE * out, FILE * err) {
|
void myfprintfStdLogMode(FILE * out, FILE * err)
|
||||||
|
{
|
||||||
myfprintf_stdLogMode = 1;
|
myfprintf_stdLogMode = 1;
|
||||||
myfprintf_out = out;
|
myfprintf_out = out;
|
||||||
myfprintf_err = err;
|
myfprintf_err = err;
|
||||||
@ -66,64 +69,68 @@ void myfprintfStdLogMode(FILE * out, FILE * err) {
|
|||||||
myfprintf_errFilename = getConfigParamValue(CONF_ERROR_FILE);
|
myfprintf_errFilename = getConfigParamValue(CONF_ERROR_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void myfprintf(FILE * fp, char * format, ... ) {
|
void myfprintf(FILE * fp, char *format, ...)
|
||||||
static char buffer[BUFFER_LENGTH+1];
|
{
|
||||||
|
static char buffer[BUFFER_LENGTH + 1];
|
||||||
va_list arglist;
|
va_list arglist;
|
||||||
int fd = fileno(fp);
|
int fd = fileno(fp);
|
||||||
|
|
||||||
va_start(arglist,format);
|
va_start(arglist, format);
|
||||||
if(fd==1 || fd==2) {
|
if (fd == 1 || fd == 2) {
|
||||||
if(myfprintf_stdLogMode) {
|
if (myfprintf_stdLogMode) {
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
if(fd==1) fp = myfprintf_out;
|
if (fd == 1)
|
||||||
else fp = myfprintf_err;
|
fp = myfprintf_out;
|
||||||
strftime(buffer,14,"%b %e %R",localtime(&t));
|
else
|
||||||
blockingWrite(fd,buffer,strlen(buffer));
|
fp = myfprintf_err;
|
||||||
blockingWrite(fd," : ",3);
|
strftime(buffer, 14, "%b %e %R", localtime(&t));
|
||||||
|
blockingWrite(fd, buffer, strlen(buffer));
|
||||||
|
blockingWrite(fd, " : ", 3);
|
||||||
}
|
}
|
||||||
vsnprintf(buffer,BUFFER_LENGTH,format,arglist);
|
vsnprintf(buffer, BUFFER_LENGTH, format, arglist);
|
||||||
blockingWrite(fd,buffer,strlen(buffer));
|
blockingWrite(fd, buffer, strlen(buffer));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int len;
|
int len;
|
||||||
vsnprintf(buffer,BUFFER_LENGTH,format,arglist);
|
vsnprintf(buffer, BUFFER_LENGTH, format, arglist);
|
||||||
len = strlen(buffer);
|
len = strlen(buffer);
|
||||||
if(interfacePrintWithFD(fd,buffer,len)<0) {
|
if (interfacePrintWithFD(fd, buffer, len) < 0) {
|
||||||
blockingWrite(fd,buffer,len);
|
blockingWrite(fd, buffer, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
va_end(arglist);
|
va_end(arglist);
|
||||||
}
|
}
|
||||||
|
|
||||||
int myfprintfCloseAndOpenLogFile(void) {
|
int myfprintfCloseAndOpenLogFile(void)
|
||||||
if(myfprintf_stdLogMode) {
|
{
|
||||||
while(fclose(myfprintf_out)<0 && errno==EINTR);
|
if (myfprintf_stdLogMode) {
|
||||||
while(fclose(myfprintf_err)<0 && errno==EINTR);
|
while (fclose(myfprintf_out) < 0 && errno == EINTR) ;
|
||||||
while((myfprintf_out = fopen(myfprintf_outFilename,"a+"))==NULL
|
while (fclose(myfprintf_err) < 0 && errno == EINTR) ;
|
||||||
&& errno==EINTR);
|
while ((myfprintf_out =
|
||||||
if(!myfprintf_out) {
|
fopen(myfprintf_outFilename, "a+")) == NULL
|
||||||
ERROR("error re-opening log file: %s\n",
|
&& errno == EINTR) ;
|
||||||
myfprintf_out);
|
if (!myfprintf_out) {
|
||||||
|
ERROR("error re-opening log file: %s\n", myfprintf_out);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
while((myfprintf_err = fopen(myfprintf_errFilename,"a+"))==NULL
|
while ((myfprintf_err =
|
||||||
&& errno==EINTR);
|
fopen(myfprintf_errFilename, "a+")) == NULL
|
||||||
if(!myfprintf_out) {
|
&& errno == EINTR) ;
|
||||||
ERROR("error re-opening log file: %s\n",
|
if (!myfprintf_out) {
|
||||||
myfprintf_out);
|
ERROR("error re-opening log file: %s\n", myfprintf_out);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
while(dup2(fileno(myfprintf_out),1)<0 && errno==EINTR);
|
while (dup2(fileno(myfprintf_out), 1) < 0 && errno == EINTR) ;
|
||||||
while(dup2(fileno(myfprintf_err),2)<0 && errno==EINTR);
|
while (dup2(fileno(myfprintf_err), 2) < 0 && errno == EINTR) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void myfprintfCloseLogFile(void) {
|
void myfprintfCloseLogFile(void)
|
||||||
if(myfprintf_stdLogMode) {
|
{
|
||||||
while(fclose(myfprintf_out)<0 && errno==EINTR);
|
if (myfprintf_stdLogMode) {
|
||||||
while(fclose(myfprintf_err)<0 && errno==EINTR);
|
while (fclose(myfprintf_out) < 0 && errno == EINTR) ;
|
||||||
|
while (fclose(myfprintf_err) < 0 && errno == EINTR) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
void myfprintfStdLogMode(FILE * out, FILE * err);
|
void myfprintfStdLogMode(FILE * out, FILE * err);
|
||||||
|
|
||||||
void myfprintf(FILE * fp, char * format, ... );
|
void myfprintf(FILE * fp, char *format, ...);
|
||||||
|
|
||||||
int myfprintfCloseAndOpenLogFile();
|
int myfprintfCloseAndOpenLogFile();
|
||||||
|
|
||||||
|
@ -30,11 +30,13 @@ static mpd_sint16 currentChunk = -1;
|
|||||||
static mpd_sint8 currentMetaChunk = -1;
|
static mpd_sint8 currentMetaChunk = -1;
|
||||||
static mpd_sint8 sendMetaChunk = 0;
|
static mpd_sint8 sendMetaChunk = 0;
|
||||||
|
|
||||||
void clearAllMetaChunkSets(OutputBuffer * cb) {
|
void clearAllMetaChunkSets(OutputBuffer * cb)
|
||||||
|
{
|
||||||
memset(cb->metaChunkSet, 0, BUFFERED_METACHUNKS);
|
memset(cb->metaChunkSet, 0, BUFFERED_METACHUNKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearOutputBuffer(OutputBuffer * cb) {
|
void clearOutputBuffer(OutputBuffer * cb)
|
||||||
|
{
|
||||||
int currentSet = 1;
|
int currentSet = 1;
|
||||||
|
|
||||||
currentChunk = -1;
|
currentChunk = -1;
|
||||||
@ -42,19 +44,20 @@ void clearOutputBuffer(OutputBuffer * cb) {
|
|||||||
|
|
||||||
/* be sure to reset metaChunkSets cause we are skipping over audio
|
/* be sure to reset metaChunkSets cause we are skipping over audio
|
||||||
* audio chunks, and thus skipping over metadata */
|
* audio chunks, and thus skipping over metadata */
|
||||||
if(sendMetaChunk == 0 && currentMetaChunk >= 0) {
|
if (sendMetaChunk == 0 && currentMetaChunk >= 0) {
|
||||||
currentSet = cb->metaChunkSet[currentChunk];
|
currentSet = cb->metaChunkSet[currentChunk];
|
||||||
}
|
}
|
||||||
clearAllMetaChunkSets(cb);
|
clearAllMetaChunkSets(cb);
|
||||||
if(sendMetaChunk == 0 && currentMetaChunk >= 0) {
|
if (sendMetaChunk == 0 && currentMetaChunk >= 0) {
|
||||||
cb->metaChunkSet[currentChunk] = currentSet;
|
cb->metaChunkSet[currentChunk] = currentSet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void flushOutputBuffer(OutputBuffer * cb) {
|
void flushOutputBuffer(OutputBuffer * cb)
|
||||||
if(currentChunk == cb->end) {
|
{
|
||||||
int next = cb->end+1;
|
if (currentChunk == cb->end) {
|
||||||
if(next>=buffered_chunks) {
|
int next = cb->end + 1;
|
||||||
|
if (next >= buffered_chunks) {
|
||||||
next = 0;
|
next = 0;
|
||||||
}
|
}
|
||||||
cb->end = next;
|
cb->end = next;
|
||||||
@ -63,85 +66,85 @@ void flushOutputBuffer(OutputBuffer * cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
|
int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
|
||||||
DecoderControl * dc, int seekable, void * dataIn,
|
DecoderControl * dc, int seekable, void *dataIn,
|
||||||
long dataInLen, float time, mpd_uint16 bitRate,
|
long dataInLen, float time, mpd_uint16 bitRate,
|
||||||
ReplayGainInfo * replayGainInfo)
|
ReplayGainInfo * replayGainInfo)
|
||||||
{
|
{
|
||||||
mpd_uint16 dataToSend;
|
mpd_uint16 dataToSend;
|
||||||
mpd_uint16 chunkLeft;
|
mpd_uint16 chunkLeft;
|
||||||
char * data;
|
char *data;
|
||||||
size_t datalen;
|
size_t datalen;
|
||||||
static char * convBuffer = NULL;
|
static char *convBuffer = NULL;
|
||||||
static long convBufferLen = 0;
|
static long convBufferLen = 0;
|
||||||
|
|
||||||
if(cmpAudioFormat(&(cb->audioFormat),&(dc->audioFormat))==0)
|
if (cmpAudioFormat(&(cb->audioFormat), &(dc->audioFormat)) == 0) {
|
||||||
{
|
|
||||||
data = dataIn;
|
data = dataIn;
|
||||||
datalen = dataInLen;
|
datalen = dataInLen;
|
||||||
}
|
} else {
|
||||||
else {
|
datalen =
|
||||||
datalen = pcm_sizeOfOutputBufferForAudioFormatConversion(
|
pcm_sizeOfOutputBufferForAudioFormatConversion(&
|
||||||
&(dc->audioFormat), dataInLen,
|
(dc->
|
||||||
&(cb->audioFormat));
|
audioFormat),
|
||||||
if(datalen > convBufferLen) {
|
dataInLen,
|
||||||
convBuffer = realloc(convBuffer,datalen);
|
&(cb->
|
||||||
|
audioFormat));
|
||||||
|
if (datalen > convBufferLen) {
|
||||||
|
convBuffer = realloc(convBuffer, datalen);
|
||||||
convBufferLen = datalen;
|
convBufferLen = datalen;
|
||||||
}
|
}
|
||||||
data = convBuffer;
|
data = convBuffer;
|
||||||
pcm_convertAudioFormat(&(dc->audioFormat), dataIn, dataInLen,
|
pcm_convertAudioFormat(&(dc->audioFormat), dataIn, dataInLen,
|
||||||
&(cb->audioFormat),data);
|
&(cb->audioFormat), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(replayGainInfo) {
|
if (replayGainInfo) {
|
||||||
doReplayGain(replayGainInfo, data, datalen, &cb->audioFormat);
|
doReplayGain(replayGainInfo, data, datalen, &cb->audioFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(datalen) {
|
while (datalen) {
|
||||||
if(currentChunk != cb->end) {
|
if (currentChunk != cb->end) {
|
||||||
int next = cb->end+1;
|
int next = cb->end + 1;
|
||||||
if(next>=buffered_chunks) {
|
if (next >= buffered_chunks) {
|
||||||
next = 0;
|
next = 0;
|
||||||
}
|
}
|
||||||
while(cb->begin==next && !dc->stop) {
|
while (cb->begin == next && !dc->stop) {
|
||||||
if(dc->seek) {
|
if (dc->seek) {
|
||||||
if(seekable) {
|
if (seekable) {
|
||||||
return OUTPUT_BUFFER_DC_SEEK;
|
return OUTPUT_BUFFER_DC_SEEK;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
dc->seekError = 1;
|
dc->seekError = 1;
|
||||||
dc->seek = 0;
|
dc->seek = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!inStream ||
|
if (!inStream ||
|
||||||
bufferInputStream(inStream) <= 0)
|
bufferInputStream(inStream) <= 0) {
|
||||||
{
|
|
||||||
my_usleep(10000);
|
my_usleep(10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(dc->stop) return OUTPUT_BUFFER_DC_STOP;
|
if (dc->stop)
|
||||||
|
return OUTPUT_BUFFER_DC_STOP;
|
||||||
|
|
||||||
currentChunk = cb->end;
|
currentChunk = cb->end;
|
||||||
cb->chunkSize[currentChunk] = 0;
|
cb->chunkSize[currentChunk] = 0;
|
||||||
|
|
||||||
if(sendMetaChunk) {
|
if (sendMetaChunk) {
|
||||||
cb->metaChunk[currentChunk] = currentMetaChunk;
|
cb->metaChunk[currentChunk] = currentMetaChunk;
|
||||||
}
|
} else
|
||||||
else cb->metaChunk[currentChunk] = -1;
|
cb->metaChunk[currentChunk] = -1;
|
||||||
cb->bitRate[currentChunk] = bitRate;
|
cb->bitRate[currentChunk] = bitRate;
|
||||||
cb->times[currentChunk] = time;
|
cb->times[currentChunk] = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
chunkLeft = CHUNK_SIZE-cb->chunkSize[currentChunk];
|
chunkLeft = CHUNK_SIZE - cb->chunkSize[currentChunk];
|
||||||
dataToSend = datalen > chunkLeft ? chunkLeft : datalen;
|
dataToSend = datalen > chunkLeft ? chunkLeft : datalen;
|
||||||
|
|
||||||
memcpy(cb->chunks+currentChunk*CHUNK_SIZE+
|
memcpy(cb->chunks + currentChunk * CHUNK_SIZE +
|
||||||
cb->chunkSize[currentChunk],
|
cb->chunkSize[currentChunk], data, dataToSend);
|
||||||
data, dataToSend);
|
cb->chunkSize[currentChunk] += dataToSend;
|
||||||
cb->chunkSize[currentChunk]+= dataToSend;
|
datalen -= dataToSend;
|
||||||
datalen-= dataToSend;
|
data += dataToSend;
|
||||||
data+= dataToSend;
|
|
||||||
|
|
||||||
if(cb->chunkSize[currentChunk] == CHUNK_SIZE) {
|
if (cb->chunkSize[currentChunk] == CHUNK_SIZE) {
|
||||||
flushOutputBuffer(cb);
|
flushOutputBuffer(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,30 +152,34 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag) {
|
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag)
|
||||||
|
{
|
||||||
int nextChunk;
|
int nextChunk;
|
||||||
static MpdTag * last = NULL;
|
static MpdTag *last = NULL;
|
||||||
|
|
||||||
if(!cb->acceptMetadata || !tag) {
|
if (!cb->acceptMetadata || !tag) {
|
||||||
sendMetaChunk = 0;
|
sendMetaChunk = 0;
|
||||||
if(last) freeMpdTag(last);
|
if (last)
|
||||||
|
freeMpdTag(last);
|
||||||
last = NULL;
|
last = NULL;
|
||||||
DEBUG("copyMpdTagToOB: !acceptMetadata || !tag\n");
|
DEBUG("copyMpdTagToOB: !acceptMetadata || !tag\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(last && mpdTagsAreEqual(last, tag)) {
|
if (last && mpdTagsAreEqual(last, tag)) {
|
||||||
DEBUG("copyMpdTagToOB: same as last\n");
|
DEBUG("copyMpdTagToOB: same as last\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(last) freeMpdTag(last);
|
if (last)
|
||||||
|
freeMpdTag(last);
|
||||||
last = NULL;
|
last = NULL;
|
||||||
|
|
||||||
nextChunk = currentMetaChunk+1;
|
nextChunk = currentMetaChunk + 1;
|
||||||
if(nextChunk >= BUFFERED_METACHUNKS) nextChunk = 0;
|
if (nextChunk >= BUFFERED_METACHUNKS)
|
||||||
|
nextChunk = 0;
|
||||||
|
|
||||||
if(cb->metaChunkSet[nextChunk]) {
|
if (cb->metaChunkSet[nextChunk]) {
|
||||||
sendMetaChunk = 0;
|
sendMetaChunk = 0;
|
||||||
DEBUG("copyMpdTagToOB: metachunk in use!\n");
|
DEBUG("copyMpdTagToOB: metachunk in use!\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -32,16 +32,16 @@
|
|||||||
#define BUFFERED_METACHUNKS 25
|
#define BUFFERED_METACHUNKS 25
|
||||||
|
|
||||||
typedef struct _OutputBuffer {
|
typedef struct _OutputBuffer {
|
||||||
char * volatile chunks;
|
char *volatile chunks;
|
||||||
mpd_uint16 * volatile chunkSize;
|
mpd_uint16 *volatile chunkSize;
|
||||||
mpd_uint16 * volatile bitRate;
|
mpd_uint16 *volatile bitRate;
|
||||||
float * volatile times;
|
float *volatile times;
|
||||||
mpd_sint16 volatile begin;
|
mpd_sint16 volatile begin;
|
||||||
mpd_sint16 volatile end;
|
mpd_sint16 volatile end;
|
||||||
AudioFormat audioFormat;
|
AudioFormat audioFormat;
|
||||||
MetadataChunk metadataChunks[BUFFERED_METACHUNKS];
|
MetadataChunk metadataChunks[BUFFERED_METACHUNKS];
|
||||||
mpd_sint8 metaChunkSet[BUFFERED_METACHUNKS];
|
mpd_sint8 metaChunkSet[BUFFERED_METACHUNKS];
|
||||||
mpd_sint8 * volatile metaChunk;
|
mpd_sint8 *volatile metaChunk;
|
||||||
volatile mpd_sint8 acceptMetadata;
|
volatile mpd_sint8 acceptMetadata;
|
||||||
} OutputBuffer;
|
} OutputBuffer;
|
||||||
|
|
||||||
@ -51,16 +51,14 @@ void flushOutputBuffer(OutputBuffer * cb);
|
|||||||
|
|
||||||
/* we send inStream for buffering the inputStream while waiting to
|
/* we send inStream for buffering the inputStream while waiting to
|
||||||
send the next chunk */
|
send the next chunk */
|
||||||
int sendDataToOutputBuffer(
|
int sendDataToOutputBuffer(OutputBuffer * cb,
|
||||||
OutputBuffer * cb,
|
|
||||||
InputStream * inStream,
|
InputStream * inStream,
|
||||||
DecoderControl * dc,
|
DecoderControl * dc,
|
||||||
int seekable,
|
int seekable,
|
||||||
void * data,
|
void *data,
|
||||||
long datalen,
|
long datalen,
|
||||||
float time,
|
float time,
|
||||||
mpd_uint16 bitRate,
|
mpd_uint16 bitRate, ReplayGainInfo * replayGainInfo);
|
||||||
ReplayGainInfo * replayGainInfo);
|
|
||||||
|
|
||||||
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag);
|
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag);
|
||||||
|
|
||||||
|
185
src/path.c
185
src/path.c
@ -37,23 +37,25 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char * musicDir;
|
char *musicDir;
|
||||||
char * playlistDir;
|
char *playlistDir;
|
||||||
|
|
||||||
char * fsCharset = NULL;
|
char *fsCharset = NULL;
|
||||||
|
|
||||||
static char * pathConvCharset(char * to, char * from, char * str) {
|
static char *pathConvCharset(char *to, char *from, char *str)
|
||||||
if(setCharSetConversion(to,from)==0) {
|
{
|
||||||
|
if (setCharSetConversion(to, from) == 0) {
|
||||||
return convStrDup(str);
|
return convStrDup(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * fsCharsetToUtf8(char * str) {
|
char *fsCharsetToUtf8(char *str)
|
||||||
char * ret = pathConvCharset("UTF-8",fsCharset,str);
|
{
|
||||||
|
char *ret = pathConvCharset("UTF-8", fsCharset, str);
|
||||||
|
|
||||||
if(ret && !validUtf8String(ret)) {
|
if (ret && !validUtf8String(ret)) {
|
||||||
free(ret);
|
free(ret);
|
||||||
ret = NULL;
|
ret = NULL;
|
||||||
}
|
}
|
||||||
@ -61,54 +63,60 @@ char * fsCharsetToUtf8(char * str) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * utf8ToFsCharset(char * str) {
|
char *utf8ToFsCharset(char *str)
|
||||||
char * ret = pathConvCharset(fsCharset,"UTF-8",str);
|
{
|
||||||
|
char *ret = pathConvCharset(fsCharset, "UTF-8", str);
|
||||||
|
|
||||||
if(!ret) ret = strdup(str);
|
if (!ret)
|
||||||
|
ret = strdup(str);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setFsCharset(char * charset) {
|
void setFsCharset(char *charset)
|
||||||
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
if(fsCharset) free(fsCharset);
|
if (fsCharset)
|
||||||
|
free(fsCharset);
|
||||||
|
|
||||||
fsCharset = strdup(charset);
|
fsCharset = strdup(charset);
|
||||||
|
|
||||||
DEBUG("setFsCharset: fs charset is: %s\n",fsCharset);
|
DEBUG("setFsCharset: fs charset is: %s\n", fsCharset);
|
||||||
|
|
||||||
if(setCharSetConversion("UTF-8",fsCharset)!=0) {
|
if (setCharSetConversion("UTF-8", fsCharset) != 0) {
|
||||||
WARNING("fs charset conversion problem: "
|
WARNING("fs charset conversion problem: "
|
||||||
"not able to convert from \"%s\" to \"%s\"\n",
|
"not able to convert from \"%s\" to \"%s\"\n",
|
||||||
fsCharset,"UTF-8");
|
fsCharset, "UTF-8");
|
||||||
error = 1;
|
error = 1;
|
||||||
}
|
}
|
||||||
if(setCharSetConversion(fsCharset,"UTF-8")!=0) {
|
if (setCharSetConversion(fsCharset, "UTF-8") != 0) {
|
||||||
WARNING("fs charset conversion problem: "
|
WARNING("fs charset conversion problem: "
|
||||||
"not able to convert from \"%s\" to \"%s\"\n",
|
"not able to convert from \"%s\" to \"%s\"\n",
|
||||||
"UTF-8",fsCharset);
|
"UTF-8", fsCharset);
|
||||||
error = 1;
|
error = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(error) {
|
if (error) {
|
||||||
free(fsCharset);
|
free(fsCharset);
|
||||||
WARNING("setting fs charset to ISO-8859-1!\n");
|
WARNING("setting fs charset to ISO-8859-1!\n");
|
||||||
fsCharset = strdup("ISO-8859-1");
|
fsCharset = strdup("ISO-8859-1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char * getFsCharset(void) {
|
char *getFsCharset(void)
|
||||||
|
{
|
||||||
return fsCharset;
|
return fsCharset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char * appendSlash(char ** path) {
|
static char *appendSlash(char **path)
|
||||||
char * temp = *path;
|
{
|
||||||
|
char *temp = *path;
|
||||||
int len = strlen(temp);
|
int len = strlen(temp);
|
||||||
|
|
||||||
if(temp[len-1] != '/') {
|
if (temp[len - 1] != '/') {
|
||||||
temp = malloc(len+2);
|
temp = malloc(len + 2);
|
||||||
memset(temp, 0, len+2);
|
memset(temp, 0, len + 2);
|
||||||
memcpy(temp, *path, len);
|
memcpy(temp, *path, len);
|
||||||
temp[len] = '/';
|
temp[len] = '/';
|
||||||
free(*path);
|
free(*path);
|
||||||
@ -118,19 +126,20 @@ static char * appendSlash(char ** path) {
|
|||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initPaths(void) {
|
void initPaths(void)
|
||||||
ConfigParam * musicParam = parseConfigFilePath(CONF_MUSIC_DIR, 1);
|
{
|
||||||
ConfigParam * playlistParam = parseConfigFilePath(CONF_PLAYLIST_DIR, 1);
|
ConfigParam *musicParam = parseConfigFilePath(CONF_MUSIC_DIR, 1);
|
||||||
ConfigParam * fsCharsetParam = getConfigParam(CONF_FS_CHARSET);
|
ConfigParam *playlistParam = parseConfigFilePath(CONF_PLAYLIST_DIR, 1);
|
||||||
|
ConfigParam *fsCharsetParam = getConfigParam(CONF_FS_CHARSET);
|
||||||
|
|
||||||
char * charset = NULL;
|
char *charset = NULL;
|
||||||
char * originalLocale;
|
char *originalLocale;
|
||||||
DIR * dir;
|
DIR *dir;
|
||||||
|
|
||||||
musicDir = appendSlash(&(musicParam->value));
|
musicDir = appendSlash(&(musicParam->value));
|
||||||
playlistDir = appendSlash(&(playlistParam->value));
|
playlistDir = appendSlash(&(playlistParam->value));
|
||||||
|
|
||||||
if((dir = opendir(playlistDir)) == NULL) {
|
if ((dir = opendir(playlistDir)) == NULL) {
|
||||||
ERROR("cannot open %s \"%s\" (config line %i): %s\n",
|
ERROR("cannot open %s \"%s\" (config line %i): %s\n",
|
||||||
CONF_PLAYLIST_DIR, playlistParam->value,
|
CONF_PLAYLIST_DIR, playlistParam->value,
|
||||||
playlistParam->line, strerror(errno));
|
playlistParam->line, strerror(errno));
|
||||||
@ -138,7 +147,7 @@ void initPaths(void) {
|
|||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
if((dir = opendir(musicDir)) == NULL) {
|
if ((dir = opendir(musicDir)) == NULL) {
|
||||||
ERROR("cannot open %s \"%s\" (config line %i): %s\n",
|
ERROR("cannot open %s \"%s\" (config line %i): %s\n",
|
||||||
CONF_MUSIC_DIR, musicParam->value,
|
CONF_MUSIC_DIR, musicParam->value,
|
||||||
musicParam->line, strerror(errno));
|
musicParam->line, strerror(errno));
|
||||||
@ -146,132 +155,136 @@ void initPaths(void) {
|
|||||||
}
|
}
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
if(fsCharsetParam) {
|
if (fsCharsetParam) {
|
||||||
charset = strdup(fsCharsetParam->value);
|
charset = strdup(fsCharsetParam->value);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_LOCALE
|
#ifdef HAVE_LOCALE
|
||||||
#ifdef HAVE_LANGINFO_CODESET
|
#ifdef HAVE_LANGINFO_CODESET
|
||||||
else if((originalLocale = setlocale(LC_CTYPE,NULL))) {
|
else if ((originalLocale = setlocale(LC_CTYPE, NULL))) {
|
||||||
char * temp;
|
char *temp;
|
||||||
char * currentLocale;
|
char *currentLocale;
|
||||||
originalLocale = strdup(originalLocale);
|
originalLocale = strdup(originalLocale);
|
||||||
|
|
||||||
if(!(currentLocale = setlocale(LC_CTYPE,""))) {
|
if (!(currentLocale = setlocale(LC_CTYPE, ""))) {
|
||||||
WARNING("problems setting current locale with "
|
WARNING("problems setting current locale with "
|
||||||
"setlocale()\n");
|
"setlocale()\n");
|
||||||
}
|
} else {
|
||||||
else {
|
if (strcmp(currentLocale, "C") == 0 ||
|
||||||
if(strcmp(currentLocale,"C")==0 ||
|
strcmp(currentLocale, "POSIX") == 0) {
|
||||||
strcmp(currentLocale,"POSIX")==0)
|
|
||||||
{
|
|
||||||
WARNING("current locale is \"%s\"\n",
|
WARNING("current locale is \"%s\"\n",
|
||||||
currentLocale);
|
currentLocale);
|
||||||
}
|
} else if ((temp = nl_langinfo(CODESET))) {
|
||||||
else if((temp = nl_langinfo(CODESET))) {
|
|
||||||
charset = strdup(temp);
|
charset = strdup(temp);
|
||||||
}
|
} else
|
||||||
else WARNING("problems getting charset for locale\n");
|
WARNING
|
||||||
if(!setlocale(LC_CTYPE,originalLocale)) {
|
("problems getting charset for locale\n");
|
||||||
WARNING("problems resetting locale with setlocale()\n");
|
if (!setlocale(LC_CTYPE, originalLocale)) {
|
||||||
|
WARNING
|
||||||
|
("problems resetting locale with setlocale()\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(originalLocale);
|
free(originalLocale);
|
||||||
}
|
} else
|
||||||
else WARNING("problems getting locale with setlocale()\n");
|
WARNING("problems getting locale with setlocale()\n");
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(charset) {
|
if (charset) {
|
||||||
setFsCharset(charset);
|
setFsCharset(charset);
|
||||||
free(charset);
|
free(charset);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
WARNING("setting filesystem charset to ISO-8859-1\n");
|
WARNING("setting filesystem charset to ISO-8859-1\n");
|
||||||
setFsCharset("ISO-8859-1");
|
setFsCharset("ISO-8859-1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishPaths(void) {
|
void finishPaths(void)
|
||||||
|
{
|
||||||
free(fsCharset);
|
free(fsCharset);
|
||||||
fsCharset = NULL;
|
fsCharset = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * rmp2amp(char * relativePath) {
|
char *rmp2amp(char *relativePath)
|
||||||
static char absolutePath[MAXPATHLEN+1];
|
{
|
||||||
|
static char absolutePath[MAXPATHLEN + 1];
|
||||||
|
|
||||||
memset(absolutePath,0,MAXPATHLEN+1);
|
memset(absolutePath, 0, MAXPATHLEN + 1);
|
||||||
|
|
||||||
strncpy(absolutePath,musicDir,MAXPATHLEN);
|
strncpy(absolutePath, musicDir, MAXPATHLEN);
|
||||||
strncat(absolutePath,relativePath,MAXPATHLEN-strlen(musicDir));
|
strncat(absolutePath, relativePath, MAXPATHLEN - strlen(musicDir));
|
||||||
|
|
||||||
return absolutePath;
|
return absolutePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * rpp2app(char * relativePath) {
|
char *rpp2app(char *relativePath)
|
||||||
static char absolutePath[MAXPATHLEN+1];
|
{
|
||||||
|
static char absolutePath[MAXPATHLEN + 1];
|
||||||
|
|
||||||
memset(absolutePath,0,MAXPATHLEN+1);
|
memset(absolutePath, 0, MAXPATHLEN + 1);
|
||||||
|
|
||||||
strncpy(absolutePath,playlistDir,MAXPATHLEN);
|
strncpy(absolutePath, playlistDir, MAXPATHLEN);
|
||||||
strncat(absolutePath,relativePath,MAXPATHLEN-strlen(musicDir));
|
strncat(absolutePath, relativePath, MAXPATHLEN - strlen(musicDir));
|
||||||
|
|
||||||
return absolutePath;
|
return absolutePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * parentPath(char * path) {
|
char *parentPath(char *path)
|
||||||
static char parentPath[MAXPATHLEN+1];
|
{
|
||||||
char * c;
|
static char parentPath[MAXPATHLEN + 1];
|
||||||
|
char *c;
|
||||||
|
|
||||||
memset(parentPath,0,MAXPATHLEN+1);
|
memset(parentPath, 0, MAXPATHLEN + 1);
|
||||||
strncpy(parentPath,path,MAXPATHLEN);
|
strncpy(parentPath, path, MAXPATHLEN);
|
||||||
|
|
||||||
c = strrchr(parentPath,'/');
|
c = strrchr(parentPath, '/');
|
||||||
if (c == NULL)
|
if (c == NULL)
|
||||||
parentPath[0] = '\0';
|
parentPath[0] = '\0';
|
||||||
else {
|
else {
|
||||||
while ((parentPath <= c) && *(--c) == '/') /* nothing */;
|
while ((parentPath <= c) && *(--c) == '/') /* nothing */
|
||||||
|
;
|
||||||
c[1] = '\0';
|
c[1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
return parentPath;
|
return parentPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * sanitizePathDup(char * path) {
|
char *sanitizePathDup(char *path)
|
||||||
int len = strlen(path)+1;
|
{
|
||||||
char * ret = malloc(len);
|
int len = strlen(path) + 1;
|
||||||
char * cp = ret;
|
char *ret = malloc(len);
|
||||||
|
char *cp = ret;
|
||||||
|
|
||||||
memset(ret,0,len);
|
memset(ret, 0, len);
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
|
|
||||||
/* illeminate more than one '/' in a row, like "///" */
|
/* illeminate more than one '/' in a row, like "///" */
|
||||||
while(*path) {
|
while (*path) {
|
||||||
while(*path=='/') path++;
|
while (*path == '/')
|
||||||
if(*path=='.') {
|
path++;
|
||||||
|
if (*path == '.') {
|
||||||
/* we dont want to have hidden directoires, or '.' or
|
/* we dont want to have hidden directoires, or '.' or
|
||||||
".." in our path */
|
".." in our path */
|
||||||
free(ret);
|
free(ret);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
while(*path && *path!='/') {
|
while (*path && *path != '/') {
|
||||||
*(cp++) = *(path++);
|
*(cp++) = *(path++);
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
if(*path=='/') {
|
if (*path == '/') {
|
||||||
*(cp++) = *(path++);
|
*(cp++) = *(path++);
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(len && ret[len-1]=='/') {
|
if (len && ret[len - 1] == '/') {
|
||||||
len--;
|
len--;
|
||||||
ret[len] = '\0';
|
ret[len] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("sanitized: %s\n", ret);
|
DEBUG("sanitized: %s\n", ret);
|
||||||
|
|
||||||
return realloc(ret,len+1);
|
return realloc(ret, len + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
src/path.h
18
src/path.h
@ -23,32 +23,32 @@
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
||||||
extern char * musicDir;
|
extern char *musicDir;
|
||||||
|
|
||||||
void initPaths();
|
void initPaths();
|
||||||
|
|
||||||
void finishPaths();
|
void finishPaths();
|
||||||
|
|
||||||
char * utf8ToFsCharset(char * str);
|
char *utf8ToFsCharset(char *str);
|
||||||
|
|
||||||
char * fsCharsetToUtf8(char * str);
|
char *fsCharsetToUtf8(char *str);
|
||||||
|
|
||||||
void setFsCharset(char * charset);
|
void setFsCharset(char *charset);
|
||||||
|
|
||||||
char * getFsCharset();
|
char *getFsCharset();
|
||||||
|
|
||||||
/* relative music path to absolute music path
|
/* relative music path to absolute music path
|
||||||
* char * passed is a static variable, so don't free it
|
* char * passed is a static variable, so don't free it
|
||||||
*/
|
*/
|
||||||
char * rmp2amp(char * file);
|
char *rmp2amp(char *file);
|
||||||
|
|
||||||
/* static char * returned */
|
/* static char * returned */
|
||||||
char * rpp2app(char * file);
|
char *rpp2app(char *file);
|
||||||
|
|
||||||
/* static char * returned */
|
/* static char * returned */
|
||||||
char * parentPath(char * path);
|
char *parentPath(char *path);
|
||||||
|
|
||||||
/* strips extra "///" and leading "/" and trailing "/" */
|
/* strips extra "///" and leading "/" and trailing "/" */
|
||||||
char * sanitizePathDup(char * path);
|
char *sanitizePathDup(char *path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
207
src/pcm_utils.c
207
src/pcm_utils.c
@ -16,7 +16,6 @@
|
|||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "pcm_utils.h"
|
#include "pcm_utils.h"
|
||||||
|
|
||||||
#include "mpd_types.h"
|
#include "mpd_types.h"
|
||||||
@ -26,39 +25,40 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
void pcm_volumeChange(char * buffer, int bufferSize, AudioFormat * format,
|
void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
|
||||||
int volume)
|
int volume)
|
||||||
{
|
{
|
||||||
mpd_sint32 temp32;
|
mpd_sint32 temp32;
|
||||||
mpd_sint8 * buffer8 = (mpd_sint8 *)buffer;
|
mpd_sint8 *buffer8 = (mpd_sint8 *) buffer;
|
||||||
mpd_sint16 * buffer16 = (mpd_sint16 *)buffer;
|
mpd_sint16 *buffer16 = (mpd_sint16 *) buffer;
|
||||||
|
|
||||||
if(volume>=1000) return;
|
if (volume >= 1000)
|
||||||
|
return;
|
||||||
|
|
||||||
if(volume<=0) {
|
if (volume <= 0) {
|
||||||
memset(buffer,0,bufferSize);
|
memset(buffer, 0, bufferSize);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(format->bits) {
|
switch (format->bits) {
|
||||||
case 16:
|
case 16:
|
||||||
while(bufferSize>0) {
|
while (bufferSize > 0) {
|
||||||
temp32 = *buffer16;
|
temp32 = *buffer16;
|
||||||
temp32*= volume;
|
temp32 *= volume;
|
||||||
temp32/=1000;
|
temp32 /= 1000;
|
||||||
*buffer16 = temp32>32767 ? 32767 :
|
*buffer16 = temp32 > 32767 ? 32767 :
|
||||||
(temp32<-32768 ? -32768 : temp32);
|
(temp32 < -32768 ? -32768 : temp32);
|
||||||
buffer16++;
|
buffer16++;
|
||||||
bufferSize-=2;
|
bufferSize -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
while(bufferSize>0) {
|
while (bufferSize > 0) {
|
||||||
temp32 = *buffer8;
|
temp32 = *buffer8;
|
||||||
temp32*= volume;
|
temp32 *= volume;
|
||||||
temp32/=1000;
|
temp32 /= 1000;
|
||||||
*buffer8 = temp32>127 ? 127 :
|
*buffer8 = temp32 > 127 ? 127 :
|
||||||
(temp32<-128 ? -128 : temp32);
|
(temp32 < -128 ? -128 : temp32);
|
||||||
buffer8++;
|
buffer8++;
|
||||||
bufferSize--;
|
bufferSize--;
|
||||||
}
|
}
|
||||||
@ -70,90 +70,98 @@ void pcm_volumeChange(char * buffer, int bufferSize, AudioFormat * format,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pcm_add(char * buffer1, char * buffer2, size_t bufferSize1,
|
static void pcm_add(char *buffer1, char *buffer2, size_t bufferSize1,
|
||||||
size_t bufferSize2, int vol1, int vol2, AudioFormat * format)
|
size_t bufferSize2, int vol1, int vol2,
|
||||||
|
AudioFormat * format)
|
||||||
{
|
{
|
||||||
mpd_sint32 temp32;
|
mpd_sint32 temp32;
|
||||||
mpd_sint8 * buffer8_1 = (mpd_sint8 *)buffer1;
|
mpd_sint8 *buffer8_1 = (mpd_sint8 *) buffer1;
|
||||||
mpd_sint8 * buffer8_2 = (mpd_sint8 *)buffer2;
|
mpd_sint8 *buffer8_2 = (mpd_sint8 *) buffer2;
|
||||||
mpd_sint16 * buffer16_1 = (mpd_sint16 *)buffer1;
|
mpd_sint16 *buffer16_1 = (mpd_sint16 *) buffer1;
|
||||||
mpd_sint16 * buffer16_2 = (mpd_sint16 *)buffer2;
|
mpd_sint16 *buffer16_2 = (mpd_sint16 *) buffer2;
|
||||||
|
|
||||||
switch(format->bits) {
|
switch (format->bits) {
|
||||||
case 16:
|
case 16:
|
||||||
while(bufferSize1>0 && bufferSize2>0) {
|
while (bufferSize1 > 0 && bufferSize2 > 0) {
|
||||||
temp32 = (vol1*(*buffer16_1)+vol2*(*buffer16_2))/1000;
|
temp32 =
|
||||||
*buffer16_1 = temp32>32767 ? 32767 :
|
(vol1 * (*buffer16_1) +
|
||||||
(temp32<-32768 ? -32768 : temp32);
|
vol2 * (*buffer16_2)) / 1000;
|
||||||
|
*buffer16_1 =
|
||||||
|
temp32 > 32767 ? 32767 : (temp32 <
|
||||||
|
-32768 ? -32768 : temp32);
|
||||||
buffer16_1++;
|
buffer16_1++;
|
||||||
buffer16_2++;
|
buffer16_2++;
|
||||||
bufferSize1-=2;
|
bufferSize1 -= 2;
|
||||||
bufferSize2-=2;
|
bufferSize2 -= 2;
|
||||||
}
|
}
|
||||||
if(bufferSize2>0) memcpy(buffer16_1,buffer16_2,bufferSize2);
|
if (bufferSize2 > 0)
|
||||||
|
memcpy(buffer16_1, buffer16_2, bufferSize2);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
while(bufferSize1>0 && bufferSize2>0) {
|
while (bufferSize1 > 0 && bufferSize2 > 0) {
|
||||||
temp32 = (vol1*(*buffer8_1)+vol2*(*buffer8_2))/1000;
|
temp32 =
|
||||||
*buffer8_1 = temp32>127 ? 127 :
|
(vol1 * (*buffer8_1) + vol2 * (*buffer8_2)) / 1000;
|
||||||
(temp32<-128 ? -128 : temp32);
|
*buffer8_1 =
|
||||||
|
temp32 > 127 ? 127 : (temp32 <
|
||||||
|
-128 ? -128 : temp32);
|
||||||
buffer8_1++;
|
buffer8_1++;
|
||||||
buffer8_2++;
|
buffer8_2++;
|
||||||
bufferSize1--;
|
bufferSize1--;
|
||||||
bufferSize2--;
|
bufferSize2--;
|
||||||
}
|
}
|
||||||
if(bufferSize2>0) memcpy(buffer8_1,buffer8_2,bufferSize2);
|
if (bufferSize2 > 0)
|
||||||
|
memcpy(buffer8_1, buffer8_2, bufferSize2);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERROR("%i bits not supported by pcm_add!\n",format->bits);
|
ERROR("%i bits not supported by pcm_add!\n", format->bits);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcm_mix(char * buffer1, char * buffer2, size_t bufferSize1,
|
void pcm_mix(char *buffer1, char *buffer2, size_t bufferSize1,
|
||||||
size_t bufferSize2, AudioFormat * format, float portion1)
|
size_t bufferSize2, AudioFormat * format, float portion1)
|
||||||
{
|
{
|
||||||
int vol1;
|
int vol1;
|
||||||
float s = sin(M_PI_2*portion1);
|
float s = sin(M_PI_2 * portion1);
|
||||||
s*=s;
|
s *= s;
|
||||||
|
|
||||||
vol1 = s*1000+0.5;
|
vol1 = s * 1000 + 0.5;
|
||||||
vol1 = vol1>1000 ? 1000 : ( vol1<0 ? 0 : vol1 );
|
vol1 = vol1 > 1000 ? 1000 : (vol1 < 0 ? 0 : vol1);
|
||||||
|
|
||||||
pcm_add(buffer1,buffer2,bufferSize1,bufferSize2,vol1,1000-vol1,format);
|
pcm_add(buffer1, buffer2, bufferSize1, bufferSize2, vol1, 1000 - vol1,
|
||||||
|
format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* outFormat bits must be 16 and channels must be 2! */
|
/* outFormat bits must be 16 and channels must be 2! */
|
||||||
void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
|
void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
|
||||||
inSize, AudioFormat * outFormat, char * outBuffer)
|
inSize, AudioFormat * outFormat, char *outBuffer)
|
||||||
{
|
{
|
||||||
static char * bitConvBuffer = NULL;
|
static char *bitConvBuffer = NULL;
|
||||||
static int bitConvBufferLength = 0;
|
static int bitConvBufferLength = 0;
|
||||||
static char * channelConvBuffer = NULL;
|
static char *channelConvBuffer = NULL;
|
||||||
static int channelConvBufferLength = 0;
|
static int channelConvBufferLength = 0;
|
||||||
char * dataChannelConv;
|
char *dataChannelConv;
|
||||||
int dataChannelLen;
|
int dataChannelLen;
|
||||||
char * dataBitConv;
|
char *dataBitConv;
|
||||||
int dataBitLen;
|
int dataBitLen;
|
||||||
|
|
||||||
assert(outFormat->bits==16);
|
assert(outFormat->bits == 16);
|
||||||
assert(outFormat->channels==2 || outFormat->channels==1);
|
assert(outFormat->channels == 2 || outFormat->channels == 1);
|
||||||
|
|
||||||
/* converts */
|
/* converts */
|
||||||
switch(inFormat->bits) {
|
switch (inFormat->bits) {
|
||||||
case 8:
|
case 8:
|
||||||
dataBitLen = inSize << 1;
|
dataBitLen = inSize << 1;
|
||||||
if(dataBitLen > bitConvBufferLength) {
|
if (dataBitLen > bitConvBufferLength) {
|
||||||
bitConvBuffer = realloc(bitConvBuffer, dataBitLen);
|
bitConvBuffer = realloc(bitConvBuffer, dataBitLen);
|
||||||
bitConvBufferLength = dataBitLen;
|
bitConvBufferLength = dataBitLen;
|
||||||
}
|
}
|
||||||
dataBitConv = bitConvBuffer;
|
dataBitConv = bitConvBuffer;
|
||||||
{
|
{
|
||||||
mpd_sint8 * in = (mpd_sint8 *)inBuffer;
|
mpd_sint8 *in = (mpd_sint8 *) inBuffer;
|
||||||
mpd_sint16 * out = (mpd_sint16 *)dataBitConv;
|
mpd_sint16 *out = (mpd_sint16 *) dataBitConv;
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<inSize; i++) {
|
for (i = 0; i < inSize; i++) {
|
||||||
*out++ = (*in++) << 8;
|
*out++ = (*in++) << 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,27 +178,26 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* converts only between 16 bit audio between mono and stereo */
|
/* converts only between 16 bit audio between mono and stereo */
|
||||||
if(inFormat->channels == outFormat->channels)
|
if (inFormat->channels == outFormat->channels) {
|
||||||
{
|
|
||||||
dataChannelConv = dataBitConv;
|
dataChannelConv = dataBitConv;
|
||||||
dataChannelLen = dataBitLen;
|
dataChannelLen = dataBitLen;
|
||||||
}
|
} else {
|
||||||
else {
|
switch (inFormat->channels) {
|
||||||
switch(inFormat->channels) {
|
|
||||||
/* convert from 1 -> 2 channels */
|
/* convert from 1 -> 2 channels */
|
||||||
case 1:
|
case 1:
|
||||||
dataChannelLen = (dataBitLen >> 1) << 2;
|
dataChannelLen = (dataBitLen >> 1) << 2;
|
||||||
if(dataChannelLen > channelConvBufferLength) {
|
if (dataChannelLen > channelConvBufferLength) {
|
||||||
channelConvBuffer = realloc(channelConvBuffer,
|
channelConvBuffer = realloc(channelConvBuffer,
|
||||||
dataChannelLen);
|
dataChannelLen);
|
||||||
channelConvBufferLength = dataChannelLen;
|
channelConvBufferLength = dataChannelLen;
|
||||||
}
|
}
|
||||||
dataChannelConv = channelConvBuffer;
|
dataChannelConv = channelConvBuffer;
|
||||||
{
|
{
|
||||||
mpd_sint16 * in = (mpd_sint16 *)dataBitConv;
|
mpd_sint16 *in = (mpd_sint16 *) dataBitConv;
|
||||||
mpd_sint16 * out = (mpd_sint16 *)dataChannelConv;
|
mpd_sint16 *out =
|
||||||
|
(mpd_sint16 *) dataChannelConv;
|
||||||
int i, inSamples = dataBitLen >> 1;
|
int i, inSamples = dataBitLen >> 1;
|
||||||
for(i=0;i<inSamples;i++) {
|
for (i = 0; i < inSamples; i++) {
|
||||||
*out++ = *in;
|
*out++ = *in;
|
||||||
*out++ = *in++;
|
*out++ = *in++;
|
||||||
}
|
}
|
||||||
@ -199,67 +206,68 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
|
|||||||
/* convert from 2 -> 1 channels */
|
/* convert from 2 -> 1 channels */
|
||||||
case 2:
|
case 2:
|
||||||
dataChannelLen = dataBitLen >> 1;
|
dataChannelLen = dataBitLen >> 1;
|
||||||
if(dataChannelLen > channelConvBufferLength) {
|
if (dataChannelLen > channelConvBufferLength) {
|
||||||
channelConvBuffer = realloc(channelConvBuffer,
|
channelConvBuffer = realloc(channelConvBuffer,
|
||||||
dataChannelLen);
|
dataChannelLen);
|
||||||
channelConvBufferLength = dataChannelLen;
|
channelConvBufferLength = dataChannelLen;
|
||||||
}
|
}
|
||||||
dataChannelConv = channelConvBuffer;
|
dataChannelConv = channelConvBuffer;
|
||||||
{
|
{
|
||||||
mpd_sint16 * in = (mpd_sint16 *)dataBitConv;
|
mpd_sint16 *in = (mpd_sint16 *) dataBitConv;
|
||||||
mpd_sint16 * out = (mpd_sint16 *)dataChannelConv;
|
mpd_sint16 *out =
|
||||||
|
(mpd_sint16 *) dataChannelConv;
|
||||||
int i, inSamples = dataBitLen >> 2;
|
int i, inSamples = dataBitLen >> 2;
|
||||||
for(i=0;i<inSamples;i++) {
|
for (i = 0; i < inSamples; i++) {
|
||||||
*out = (*in++)/2;
|
*out = (*in++) / 2;
|
||||||
*out++ += (*in++)/2;
|
*out++ += (*in++) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERROR("only 1 or 2 channels are supported for conversion!\n");
|
ERROR
|
||||||
|
("only 1 or 2 channels are supported for conversion!\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inFormat->sampleRate == outFormat->sampleRate) {
|
if (inFormat->sampleRate == outFormat->sampleRate) {
|
||||||
memcpy(outBuffer,dataChannelConv,dataChannelLen);
|
memcpy(outBuffer, dataChannelConv, dataChannelLen);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
/* only works if outFormat is 16-bit stereo! */
|
/* only works if outFormat is 16-bit stereo! */
|
||||||
/* resampling code blatantly ripped from ESD */
|
/* resampling code blatantly ripped from ESD */
|
||||||
mpd_uint32 rd_dat = 0;
|
mpd_uint32 rd_dat = 0;
|
||||||
mpd_uint32 wr_dat = 0;
|
mpd_uint32 wr_dat = 0;
|
||||||
mpd_sint16 lsample, rsample;
|
mpd_sint16 lsample, rsample;
|
||||||
mpd_sint16 * out = (mpd_sint16 *)outBuffer;
|
mpd_sint16 *out = (mpd_sint16 *) outBuffer;
|
||||||
mpd_sint16 * in = (mpd_sint16 *)dataChannelConv;
|
mpd_sint16 *in = (mpd_sint16 *) dataChannelConv;
|
||||||
const int shift = sizeof(mpd_sint16)*outFormat->channels;
|
const int shift = sizeof(mpd_sint16) * outFormat->channels;
|
||||||
mpd_uint32 nlen = ((( dataChannelLen / shift) *
|
mpd_uint32 nlen = (((dataChannelLen / shift) *
|
||||||
(mpd_uint32)(outFormat->sampleRate)) /
|
(mpd_uint32) (outFormat->sampleRate)) /
|
||||||
inFormat->sampleRate);
|
inFormat->sampleRate);
|
||||||
nlen *= outFormat->channels;
|
nlen *= outFormat->channels;
|
||||||
|
|
||||||
switch(outFormat->channels) {
|
switch (outFormat->channels) {
|
||||||
case 1:
|
case 1:
|
||||||
while( wr_dat < nlen) {
|
while (wr_dat < nlen) {
|
||||||
rd_dat = wr_dat * inFormat->sampleRate /
|
rd_dat = wr_dat * inFormat->sampleRate /
|
||||||
outFormat->sampleRate;
|
outFormat->sampleRate;
|
||||||
|
|
||||||
lsample = in[ rd_dat++ ];
|
lsample = in[rd_dat++];
|
||||||
|
|
||||||
out[ wr_dat++ ] = lsample;
|
out[wr_dat++] = lsample;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
while( wr_dat < nlen) {
|
while (wr_dat < nlen) {
|
||||||
rd_dat = wr_dat * inFormat->sampleRate /
|
rd_dat = wr_dat * inFormat->sampleRate /
|
||||||
outFormat->sampleRate;
|
outFormat->sampleRate;
|
||||||
rd_dat &= ~1;
|
rd_dat &= ~1;
|
||||||
|
|
||||||
lsample = in[ rd_dat++ ];
|
lsample = in[rd_dat++];
|
||||||
rsample = in[ rd_dat++ ];
|
rsample = in[rd_dat++];
|
||||||
|
|
||||||
out[ wr_dat++ ] = lsample;
|
out[wr_dat++] = lsample;
|
||||||
out[ wr_dat++ ] = rsample;
|
out[wr_dat++] = rsample;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -269,12 +277,13 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
|
size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
|
||||||
size_t inSize, AudioFormat * outFormat)
|
size_t inSize,
|
||||||
|
AudioFormat * outFormat)
|
||||||
{
|
{
|
||||||
const int shift = sizeof(mpd_sint16)*outFormat->channels;
|
const int shift = sizeof(mpd_sint16) * outFormat->channels;
|
||||||
size_t outSize = inSize;
|
size_t outSize = inSize;
|
||||||
|
|
||||||
switch(inFormat->bits) {
|
switch (inFormat->bits) {
|
||||||
case 8:
|
case 8:
|
||||||
outSize = outSize << 1;
|
outSize = outSize << 1;
|
||||||
break;
|
break;
|
||||||
@ -285,8 +294,8 @@ size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(inFormat->channels != outFormat->channels) {
|
if (inFormat->channels != outFormat->channels) {
|
||||||
switch(inFormat->channels) {
|
switch (inFormat->channels) {
|
||||||
case 1:
|
case 1:
|
||||||
outSize = (outSize >> 1) << 2;
|
outSize = (outSize >> 1) << 2;
|
||||||
break;
|
break;
|
||||||
@ -296,7 +305,7 @@ size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outSize = (((outSize / shift) * (mpd_uint32)(outFormat->sampleRate)) /
|
outSize = (((outSize / shift) * (mpd_uint32) (outFormat->sampleRate)) /
|
||||||
inFormat->sampleRate);
|
inFormat->sampleRate);
|
||||||
|
|
||||||
outSize *= shift;
|
outSize *= shift;
|
||||||
|
@ -25,15 +25,16 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
void pcm_volumeChange(char * buffer, int bufferSize, AudioFormat * format,
|
void pcm_volumeChange(char *buffer, int bufferSize, AudioFormat * format,
|
||||||
int volume);
|
int volume);
|
||||||
|
|
||||||
void pcm_mix(char * buffer1, char * buffer2, size_t bufferSize1,
|
void pcm_mix(char *buffer1, char *buffer2, size_t bufferSize1,
|
||||||
size_t bufferSize2, AudioFormat * format, float portion1);
|
size_t bufferSize2, AudioFormat * format, float portion1);
|
||||||
|
|
||||||
void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
|
void pcm_convertAudioFormat(AudioFormat * inFormat, char *inBuffer, size_t
|
||||||
inSize, AudioFormat * outFormat, char * outBuffer);
|
inSize, AudioFormat * outFormat, char *outBuffer);
|
||||||
|
|
||||||
size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
|
size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
|
||||||
size_t inSize, AudioFormat * outFormat);
|
size_t inSize,
|
||||||
|
AudioFormat * outFormat);
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,48 +32,47 @@
|
|||||||
#define PERMISSION_CONTROL_STRING "control"
|
#define PERMISSION_CONTROL_STRING "control"
|
||||||
#define PERMISSION_ADMIN_STRING "admin"
|
#define PERMISSION_ADMIN_STRING "admin"
|
||||||
|
|
||||||
static List * permission_passwords;
|
static List *permission_passwords;
|
||||||
|
|
||||||
static int permission_default;
|
static int permission_default;
|
||||||
|
|
||||||
static int parsePermissions(char * string) {
|
static int parsePermissions(char *string)
|
||||||
|
{
|
||||||
int permission = 0;
|
int permission = 0;
|
||||||
char * temp;
|
char *temp;
|
||||||
char * tok;
|
char *tok;
|
||||||
|
|
||||||
if(!string) return 0;
|
if (!string)
|
||||||
|
return 0;
|
||||||
|
|
||||||
temp = strtok_r(string,PERMISSION_SEPERATOR,&tok);
|
temp = strtok_r(string, PERMISSION_SEPERATOR, &tok);
|
||||||
while(temp) {
|
while (temp) {
|
||||||
if(strcmp(temp,PERMISSION_READ_STRING)==0) {
|
if (strcmp(temp, PERMISSION_READ_STRING) == 0) {
|
||||||
permission |= PERMISSION_READ;
|
permission |= PERMISSION_READ;
|
||||||
}
|
} else if (strcmp(temp, PERMISSION_ADD_STRING) == 0) {
|
||||||
else if(strcmp(temp,PERMISSION_ADD_STRING)==0) {
|
|
||||||
permission |= PERMISSION_ADD;
|
permission |= PERMISSION_ADD;
|
||||||
}
|
} else if (strcmp(temp, PERMISSION_CONTROL_STRING) == 0) {
|
||||||
else if(strcmp(temp,PERMISSION_CONTROL_STRING)==0) {
|
|
||||||
permission |= PERMISSION_CONTROL;
|
permission |= PERMISSION_CONTROL;
|
||||||
}
|
} else if (strcmp(temp, PERMISSION_ADMIN_STRING) == 0) {
|
||||||
else if(strcmp(temp,PERMISSION_ADMIN_STRING)==0) {
|
|
||||||
permission |= PERMISSION_ADMIN;
|
permission |= PERMISSION_ADMIN;
|
||||||
}
|
} else {
|
||||||
else {
|
ERROR("unknown permission \"%s\"\n", temp);
|
||||||
ERROR("unknown permission \"%s\"\n",temp);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
temp = strtok_r(NULL,PERMISSION_SEPERATOR,&tok);
|
temp = strtok_r(NULL, PERMISSION_SEPERATOR, &tok);
|
||||||
}
|
}
|
||||||
|
|
||||||
return permission;
|
return permission;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initPermissions(void) {
|
void initPermissions(void)
|
||||||
char * temp;
|
{
|
||||||
char * cp2;
|
char *temp;
|
||||||
char * password;
|
char *cp2;
|
||||||
int * permission;
|
char *password;
|
||||||
ConfigParam * param;
|
int *permission;
|
||||||
|
ConfigParam *param;
|
||||||
|
|
||||||
permission_passwords = makeList(free, 1);
|
permission_passwords = makeList(free, 1);
|
||||||
|
|
||||||
@ -82,46 +81,50 @@ void initPermissions(void) {
|
|||||||
|
|
||||||
param = getNextConfigParam(CONF_PASSWORD, NULL);
|
param = getNextConfigParam(CONF_PASSWORD, NULL);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
permission_default = 0;
|
permission_default = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if(!strstr(param->value, PERMISSION_PASSWORD_CHAR)) {
|
if (!strstr(param->value, PERMISSION_PASSWORD_CHAR)) {
|
||||||
ERROR("\"%s\" not found in password string "
|
ERROR("\"%s\" not found in password string "
|
||||||
"\"%s\", line %i\n",
|
"\"%s\", line %i\n",
|
||||||
PERMISSION_PASSWORD_CHAR,
|
PERMISSION_PASSWORD_CHAR,
|
||||||
param->value,
|
param->value, param->line);
|
||||||
param->line);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(temp = strtok_r(param->value,
|
if (!(temp = strtok_r(param->value,
|
||||||
PERMISSION_PASSWORD_CHAR,&cp2))) {
|
PERMISSION_PASSWORD_CHAR,
|
||||||
ERROR("something weird just happened in permission.c\n");
|
&cp2))) {
|
||||||
|
ERROR
|
||||||
|
("something weird just happened in permission.c\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
password = temp;
|
password = temp;
|
||||||
|
|
||||||
permission = malloc(sizeof(int));
|
permission = malloc(sizeof(int));
|
||||||
*permission = parsePermissions(strtok_r(NULL,"",&cp2));
|
*permission =
|
||||||
|
parsePermissions(strtok_r(NULL, "", &cp2));
|
||||||
|
|
||||||
insertInList(permission_passwords,password,permission);
|
insertInList(permission_passwords, password,
|
||||||
} while((param = getNextConfigParam(CONF_PASSWORD, param)));
|
permission);
|
||||||
|
} while ((param = getNextConfigParam(CONF_PASSWORD, param)));
|
||||||
}
|
}
|
||||||
|
|
||||||
param = getConfigParam(CONF_DEFAULT_PERMS);
|
param = getConfigParam(CONF_DEFAULT_PERMS);
|
||||||
|
|
||||||
if(param) permission_default = parsePermissions(param->value);
|
if (param)
|
||||||
|
permission_default = parsePermissions(param->value);
|
||||||
|
|
||||||
sortList(permission_passwords);
|
sortList(permission_passwords);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPermissionFromPassword(char * password, int * permission) {
|
int getPermissionFromPassword(char *password, int *permission)
|
||||||
void * foundPermission;
|
{
|
||||||
|
void *foundPermission;
|
||||||
|
|
||||||
if(findInList(permission_passwords,password,&foundPermission)) {
|
if (findInList(permission_passwords, password, &foundPermission)) {
|
||||||
*permission = *((int *)foundPermission);
|
*permission = *((int *)foundPermission);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -129,10 +132,12 @@ int getPermissionFromPassword(char * password, int * permission) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishPermissions(void) {
|
void finishPermissions(void)
|
||||||
|
{
|
||||||
freeList(permission_passwords);
|
freeList(permission_passwords);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getDefaultPermissions(void) {
|
int getDefaultPermissions(void)
|
||||||
|
{
|
||||||
return permission_default;
|
return permission_default;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
void initPermissions();
|
void initPermissions();
|
||||||
|
|
||||||
int getPermissionFromPassword(char * password, int * permission);
|
int getPermissionFromPassword(char *password, int *permission);
|
||||||
|
|
||||||
void finishPermissions();
|
void finishPermissions();
|
||||||
|
|
||||||
|
339
src/player.c
339
src/player.c
@ -45,15 +45,17 @@
|
|||||||
|
|
||||||
extern int masterPid;
|
extern int masterPid;
|
||||||
|
|
||||||
static void resetPlayerMetadata() {
|
static void resetPlayerMetadata()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(pc->metadataState == PLAYER_METADATA_STATE_READ) {
|
if (pc->metadataState == PLAYER_METADATA_STATE_READ) {
|
||||||
pc->metadataState = PLAYER_METADATA_STATE_WRITE;
|
pc->metadataState = PLAYER_METADATA_STATE_WRITE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetPlayer() {
|
void resetPlayer()
|
||||||
|
{
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
setPlayerPid(0);
|
setPlayerPid(0);
|
||||||
@ -68,85 +70,85 @@ void resetPlayer() {
|
|||||||
getPlayerData()->playerControl.metadataState =
|
getPlayerData()->playerControl.metadataState =
|
||||||
PLAYER_METADATA_STATE_WRITE;
|
PLAYER_METADATA_STATE_WRITE;
|
||||||
pid = getPlayerData()->playerControl.decode_pid;
|
pid = getPlayerData()->playerControl.decode_pid;
|
||||||
if(pid>0) kill(pid,SIGTERM);
|
if (pid > 0)
|
||||||
|
kill(pid, SIGTERM);
|
||||||
getPlayerData()->playerControl.decode_pid = 0;
|
getPlayerData()->playerControl.decode_pid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void player_sigChldHandler(int pid, int status) {
|
void player_sigChldHandler(int pid, int status)
|
||||||
if(getPlayerPid()==pid) {
|
{
|
||||||
|
if (getPlayerPid() == pid) {
|
||||||
DEBUG("SIGCHLD caused by player process\n");
|
DEBUG("SIGCHLD caused by player process\n");
|
||||||
if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM &&
|
if (WIFSIGNALED(status) && WTERMSIG(status) != SIGTERM &&
|
||||||
WTERMSIG(status)!=SIGINT)
|
WTERMSIG(status) != SIGINT) {
|
||||||
{
|
|
||||||
ERROR("player process died from signal: %i\n",
|
ERROR("player process died from signal: %i\n",
|
||||||
WTERMSIG(status));
|
WTERMSIG(status));
|
||||||
}
|
}
|
||||||
resetPlayer();
|
resetPlayer();
|
||||||
}
|
} else if (pid == getPlayerData()->playerControl.decode_pid
|
||||||
else if(pid==getPlayerData()->playerControl.decode_pid && getPlayerPid()<=0)
|
&& getPlayerPid() <= 0) {
|
||||||
{
|
if (WIFSIGNALED(status) && WTERMSIG(status) != SIGTERM) {
|
||||||
if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM) {
|
|
||||||
ERROR("(caught by master parent) "
|
ERROR("(caught by master parent) "
|
||||||
"decode process died from a "
|
"decode process died from a "
|
||||||
"non-TERM signal: %i\n",
|
"non-TERM signal: %i\n", WTERMSIG(status));
|
||||||
WTERMSIG(status));
|
|
||||||
}
|
}
|
||||||
getPlayerData()->playerControl.decode_pid = 0;
|
getPlayerData()->playerControl.decode_pid = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int playerInit() {
|
int playerInit()
|
||||||
|
{
|
||||||
kill(masterPid, SIGUSR2);
|
kill(masterPid, SIGUSR2);
|
||||||
/* we need to wait for the signal to take effect: */
|
/* we need to wait for the signal to take effect: */
|
||||||
while (getPlayerPid()==0) my_usleep(10000);
|
while (getPlayerPid() == 0)
|
||||||
|
my_usleep(10000);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int playerInitReal() {
|
int playerInitReal()
|
||||||
|
{
|
||||||
int player_pid;
|
int player_pid;
|
||||||
blockSignals();
|
blockSignals();
|
||||||
player_pid = fork();
|
player_pid = fork();
|
||||||
if(player_pid==0) {
|
if (player_pid == 0) {
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
unblockSignals();
|
unblockSignals();
|
||||||
|
|
||||||
setSigHandlersForDecoder();
|
setSigHandlersForDecoder();
|
||||||
|
|
||||||
while(1) {
|
while (1) {
|
||||||
if(pc->play) decode();
|
if (pc->play)
|
||||||
else if(pc->stop) pc->stop = 0;
|
decode();
|
||||||
else if(pc->pause) pc->pause = 0;
|
else if (pc->stop)
|
||||||
else if(pc->closeAudio) {
|
pc->stop = 0;
|
||||||
|
else if (pc->pause)
|
||||||
|
pc->pause = 0;
|
||||||
|
else if (pc->closeAudio) {
|
||||||
closeAudioDevice();
|
closeAudioDevice();
|
||||||
pc->closeAudio = 0;
|
pc->closeAudio = 0;
|
||||||
kill(getppid(),SIGUSR1);
|
kill(getppid(), SIGUSR1);
|
||||||
}
|
} else if (pc->lockQueue) {
|
||||||
else if(pc->lockQueue) {
|
|
||||||
pc->queueLockState = PLAYER_QUEUE_LOCKED;
|
pc->queueLockState = PLAYER_QUEUE_LOCKED;
|
||||||
pc->lockQueue = 0;
|
pc->lockQueue = 0;
|
||||||
}
|
} else if (pc->unlockQueue) {
|
||||||
else if(pc->unlockQueue) {
|
|
||||||
pc->queueLockState = PLAYER_QUEUE_UNLOCKED;
|
pc->queueLockState = PLAYER_QUEUE_UNLOCKED;
|
||||||
pc->unlockQueue = 0;
|
pc->unlockQueue = 0;
|
||||||
}
|
} else if (pc->cycleLogFiles) {
|
||||||
else if(pc->cycleLogFiles) {
|
|
||||||
myfprintfCloseAndOpenLogFile();
|
myfprintfCloseAndOpenLogFile();
|
||||||
pc->cycleLogFiles = 0;
|
pc->cycleLogFiles = 0;
|
||||||
}
|
} else
|
||||||
else my_usleep(10000);
|
my_usleep(10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
}
|
} else if (player_pid < 0) {
|
||||||
else if(player_pid<0) {
|
|
||||||
unblockSignals();
|
unblockSignals();
|
||||||
ERROR("player Problems fork()'ing\n");
|
ERROR("player Problems fork()'ing\n");
|
||||||
setPlayerPid(0);
|
setPlayerPid(0);
|
||||||
player_pid = 0;
|
player_pid = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
setPlayerPid(player_pid);
|
setPlayerPid(player_pid);
|
||||||
|
|
||||||
unblockSignals();
|
unblockSignals();
|
||||||
@ -154,15 +156,20 @@ int playerInitReal() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int playerPlay(FILE * fp, Song * song) {
|
int playerPlay(FILE * fp, Song * song)
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(fp==NULL) fp = stderr;
|
if (fp == NULL)
|
||||||
|
fp = stderr;
|
||||||
|
|
||||||
if(playerStop(fp)<0) return -1;
|
if (playerStop(fp) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if(song->tag) pc->fileTime = song->tag->time;
|
if (song->tag)
|
||||||
else pc->fileTime = 0;
|
pc->fileTime = song->tag->time;
|
||||||
|
else
|
||||||
|
pc->fileTime = 0;
|
||||||
|
|
||||||
copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
|
copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
|
||||||
|
|
||||||
@ -170,23 +177,26 @@ int playerPlay(FILE * fp, Song * song) {
|
|||||||
pc->utf8url[MAXPATHLEN] = '\0';
|
pc->utf8url[MAXPATHLEN] = '\0';
|
||||||
|
|
||||||
pc->play = 1;
|
pc->play = 1;
|
||||||
if(getPlayerPid()==0 && playerInit()<0) {
|
if (getPlayerPid() == 0 && playerInit() < 0) {
|
||||||
pc->play = 0;
|
pc->play = 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetPlayerMetadata();
|
resetPlayerMetadata();
|
||||||
while(getPlayerPid()>0 && pc->play) my_usleep(1000);
|
while (getPlayerPid() > 0 && pc->play)
|
||||||
|
my_usleep(1000);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int playerStop(FILE * fp) {
|
int playerStop(FILE * fp)
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(getPlayerPid()>0 && pc->state!=PLAYER_STATE_STOP) {
|
if (getPlayerPid() > 0 && pc->state != PLAYER_STATE_STOP) {
|
||||||
pc->stop = 1;
|
pc->stop = 1;
|
||||||
while(getPlayerPid()>0 && pc->stop) my_usleep(1000);
|
while (getPlayerPid() > 0 && pc->stop)
|
||||||
|
my_usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
pc->queueState = PLAYER_QUEUE_BLANK;
|
pc->queueState = PLAYER_QUEUE_BLANK;
|
||||||
@ -195,127 +205,148 @@ int playerStop(FILE * fp) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void playerKill() {
|
void playerKill()
|
||||||
|
{
|
||||||
int pid;
|
int pid;
|
||||||
/*PlayerControl * pc = &(getPlayerData()->playerControl);
|
/*PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
playerStop(stderr);
|
playerStop(stderr);
|
||||||
playerCloseAudio(stderr);
|
playerCloseAudio(stderr);
|
||||||
if(player_pid>0 && pc->closeAudio) sleep(1);*/
|
if(player_pid>0 && pc->closeAudio) sleep(1); */
|
||||||
|
|
||||||
pid = getPlayerPid();
|
pid = getPlayerPid();
|
||||||
if(pid>0) kill(pid,SIGTERM);
|
if (pid > 0)
|
||||||
|
kill(pid, SIGTERM);
|
||||||
}
|
}
|
||||||
|
|
||||||
int playerPause(FILE * fp) {
|
int playerPause(FILE * fp)
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(getPlayerPid()>0 && pc->state!=PLAYER_STATE_STOP) {
|
if (getPlayerPid() > 0 && pc->state != PLAYER_STATE_STOP) {
|
||||||
pc->pause = 1;
|
pc->pause = 1;
|
||||||
while(getPlayerPid()>0 && pc->pause) my_usleep(1000);
|
while (getPlayerPid() > 0 && pc->pause)
|
||||||
|
my_usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int playerSetPause(FILE * fp, int pause) {
|
int playerSetPause(FILE * fp, int pause)
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(getPlayerPid()<=0) return 0;
|
if (getPlayerPid() <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
switch(pc->state) {
|
switch (pc->state) {
|
||||||
case PLAYER_STATE_PLAY:
|
case PLAYER_STATE_PLAY:
|
||||||
if(pause) playerPause(fp);
|
if (pause)
|
||||||
|
playerPause(fp);
|
||||||
break;
|
break;
|
||||||
case PLAYER_STATE_PAUSE:
|
case PLAYER_STATE_PAUSE:
|
||||||
if(!pause) playerPause(fp);
|
if (!pause)
|
||||||
|
playerPause(fp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPlayerElapsedTime() {
|
int getPlayerElapsedTime()
|
||||||
return (int)(getPlayerData()->playerControl.elapsedTime+0.5);
|
{
|
||||||
|
return (int)(getPlayerData()->playerControl.elapsedTime + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long getPlayerBitRate() {
|
unsigned long getPlayerBitRate()
|
||||||
|
{
|
||||||
return getPlayerData()->playerControl.bitRate;
|
return getPlayerData()->playerControl.bitRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPlayerTotalTime() {
|
int getPlayerTotalTime()
|
||||||
return (int)(getPlayerData()->playerControl.totalTime+0.5);
|
{
|
||||||
|
return (int)(getPlayerData()->playerControl.totalTime + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPlayerState() {
|
int getPlayerState()
|
||||||
|
{
|
||||||
return getPlayerData()->playerControl.state;
|
return getPlayerData()->playerControl.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearPlayerError() {
|
void clearPlayerError()
|
||||||
|
{
|
||||||
getPlayerData()->playerControl.error = 0;
|
getPlayerData()->playerControl.error = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPlayerError() {
|
int getPlayerError()
|
||||||
|
{
|
||||||
return getPlayerData()->playerControl.error;
|
return getPlayerData()->playerControl.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * getPlayerErrorStr() {
|
char *getPlayerErrorStr()
|
||||||
static char * error = NULL;
|
{
|
||||||
int errorlen = MAXPATHLEN+1024;
|
static char *error = NULL;
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
int errorlen = MAXPATHLEN + 1024;
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
error = realloc(error,errorlen+1);
|
error = realloc(error, errorlen + 1);
|
||||||
memset(error,0,errorlen+1);
|
memset(error, 0, errorlen + 1);
|
||||||
|
|
||||||
switch(pc->error) {
|
switch (pc->error) {
|
||||||
case PLAYER_ERROR_FILENOTFOUND:
|
case PLAYER_ERROR_FILENOTFOUND:
|
||||||
snprintf(error,errorlen,
|
snprintf(error, errorlen,
|
||||||
"file \"%s\" does not exist or is inaccesible",
|
"file \"%s\" does not exist or is inaccesible",
|
||||||
pc->erroredUrl);
|
pc->erroredUrl);
|
||||||
break;
|
break;
|
||||||
case PLAYER_ERROR_FILE:
|
case PLAYER_ERROR_FILE:
|
||||||
snprintf(error,errorlen,"problems decoding \"%s\"",
|
snprintf(error, errorlen, "problems decoding \"%s\"",
|
||||||
pc->erroredUrl);
|
pc->erroredUrl);
|
||||||
break;
|
break;
|
||||||
case PLAYER_ERROR_AUDIO:
|
case PLAYER_ERROR_AUDIO:
|
||||||
snprintf(error,errorlen,"problems opening audio device");
|
snprintf(error, errorlen, "problems opening audio device");
|
||||||
break;
|
break;
|
||||||
case PLAYER_ERROR_SYSTEM:
|
case PLAYER_ERROR_SYSTEM:
|
||||||
snprintf(error,errorlen,"system error occured");
|
snprintf(error, errorlen, "system error occured");
|
||||||
break;
|
break;
|
||||||
case PLAYER_ERROR_UNKTYPE:
|
case PLAYER_ERROR_UNKTYPE:
|
||||||
snprintf(error,errorlen,"file type of \"%s\" is unknown",
|
snprintf(error, errorlen, "file type of \"%s\" is unknown",
|
||||||
pc->erroredUrl);
|
pc->erroredUrl);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
errorlen = strlen(error);
|
errorlen = strlen(error);
|
||||||
error = realloc(error,errorlen+1);
|
error = realloc(error, errorlen + 1);
|
||||||
|
|
||||||
if(errorlen) return error;
|
if (errorlen)
|
||||||
|
return error;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void playerCloseAudio() {
|
void playerCloseAudio()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(getPlayerPid()>0) {
|
if (getPlayerPid() > 0) {
|
||||||
if(playerStop(stderr)<0) return;
|
if (playerStop(stderr) < 0)
|
||||||
|
return;
|
||||||
pc->closeAudio = 1;
|
pc->closeAudio = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int queueSong(Song * song) {
|
int queueSong(Song * song)
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(pc->queueState==PLAYER_QUEUE_BLANK) {
|
if (pc->queueState == PLAYER_QUEUE_BLANK) {
|
||||||
strncpy(pc->utf8url, getSongUrl(song), MAXPATHLEN);
|
strncpy(pc->utf8url, getSongUrl(song), MAXPATHLEN);
|
||||||
pc->utf8url[MAXPATHLEN] = '\0';
|
pc->utf8url[MAXPATHLEN] = '\0';
|
||||||
|
|
||||||
if(song->tag) pc->fileTime = song->tag->time;
|
if (song->tag)
|
||||||
else pc->fileTime = 0;
|
pc->fileTime = song->tag->time;
|
||||||
|
else
|
||||||
|
pc->fileTime = 0;
|
||||||
|
|
||||||
copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
|
copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
|
||||||
|
|
||||||
@ -326,50 +357,57 @@ int queueSong(Song * song) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPlayerQueueState() {
|
int getPlayerQueueState()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
return pc->queueState;
|
return pc->queueState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setQueueState(int queueState) {
|
void setQueueState(int queueState)
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
pc->queueState = queueState;
|
pc->queueState = queueState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void playerQueueLock() {
|
void playerQueueLock()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(getPlayerPid()>0 && pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
|
if (getPlayerPid() > 0 && pc->queueLockState == PLAYER_QUEUE_UNLOCKED) {
|
||||||
{
|
|
||||||
pc->lockQueue = 1;
|
pc->lockQueue = 1;
|
||||||
while(getPlayerPid()>0 && pc->lockQueue) my_usleep(1000);
|
while (getPlayerPid() > 0 && pc->lockQueue)
|
||||||
|
my_usleep(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void playerQueueUnlock() {
|
void playerQueueUnlock()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(getPlayerPid()>0 && pc->queueLockState==PLAYER_QUEUE_LOCKED)
|
if (getPlayerPid() > 0 && pc->queueLockState == PLAYER_QUEUE_LOCKED) {
|
||||||
{
|
|
||||||
pc->unlockQueue = 1;
|
pc->unlockQueue = 1;
|
||||||
while(getPlayerPid()>0 && pc->unlockQueue) my_usleep(1000);
|
while (getPlayerPid() > 0 && pc->unlockQueue)
|
||||||
|
my_usleep(1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int playerSeek(FILE * fp, Song * song, float time) {
|
int playerSeek(FILE * fp, Song * song, float time)
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(pc->state==PLAYER_STATE_STOP) {
|
if (pc->state == PLAYER_STATE_STOP) {
|
||||||
commandError(fp, ACK_ERROR_PLAYER_SYNC,
|
commandError(fp, ACK_ERROR_PLAYER_SYNC,
|
||||||
"player not currently playing", NULL);
|
"player not currently playing", NULL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strcmp(pc->utf8url, getSongUrl(song))!=0) {
|
if (strcmp(pc->utf8url, getSongUrl(song)) != 0) {
|
||||||
if(song->tag) pc->fileTime = song->tag->time;
|
if (song->tag)
|
||||||
else pc->fileTime = 0;
|
pc->fileTime = song->tag->time;
|
||||||
|
else
|
||||||
|
pc->fileTime = 0;
|
||||||
|
|
||||||
copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
|
copyMpdTagToMetadataChunk(song->tag, &(pc->fileMetadataChunk));
|
||||||
|
|
||||||
@ -377,85 +415,98 @@ int playerSeek(FILE * fp, Song * song, float time) {
|
|||||||
pc->utf8url[MAXPATHLEN] = '\0';
|
pc->utf8url[MAXPATHLEN] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pc->error==PLAYER_ERROR_NOERROR) {
|
if (pc->error == PLAYER_ERROR_NOERROR) {
|
||||||
resetPlayerMetadata();
|
resetPlayerMetadata();
|
||||||
pc->seekWhere = time;
|
pc->seekWhere = time;
|
||||||
pc->seek = 1;
|
pc->seek = 1;
|
||||||
while(getPlayerPid()>0 && pc->seek) my_usleep(1000);
|
while (getPlayerPid() > 0 && pc->seek)
|
||||||
|
my_usleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getPlayerCrossFade() {
|
float getPlayerCrossFade()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
return pc->crossFade;
|
return pc->crossFade;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPlayerCrossFade(float crossFadeInSeconds) {
|
void setPlayerCrossFade(float crossFadeInSeconds)
|
||||||
PlayerControl * pc;
|
{
|
||||||
if(crossFadeInSeconds<0) crossFadeInSeconds = 0;
|
PlayerControl *pc;
|
||||||
|
if (crossFadeInSeconds < 0)
|
||||||
|
crossFadeInSeconds = 0;
|
||||||
|
|
||||||
pc = &(getPlayerData()->playerControl);
|
pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
pc->crossFade = crossFadeInSeconds;
|
pc->crossFade = crossFadeInSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPlayerSoftwareVolume(int volume) {
|
void setPlayerSoftwareVolume(int volume)
|
||||||
PlayerControl * pc;
|
{
|
||||||
volume = (volume>1000) ? 1000 : (volume<0 ? 0 : volume);
|
PlayerControl *pc;
|
||||||
|
volume = (volume > 1000) ? 1000 : (volume < 0 ? 0 : volume);
|
||||||
|
|
||||||
pc = &(getPlayerData()->playerControl);
|
pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
pc->softwareVolume = volume;
|
pc->softwareVolume = volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
double getPlayerTotalPlayTime() {
|
double getPlayerTotalPlayTime()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
return pc->totalPlayTime;
|
return pc->totalPlayTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int getPlayerSampleRate() {
|
unsigned int getPlayerSampleRate()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
return pc->sampleRate;
|
return pc->sampleRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPlayerBits() {
|
int getPlayerBits()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
return pc->bits;
|
return pc->bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPlayerChannels() {
|
int getPlayerChannels()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
return pc->channels;
|
return pc->channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
void playerCycleLogFiles() {
|
void playerCycleLogFiles()
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
{
|
||||||
DecoderControl * dc = &(getPlayerData()->decoderControl);
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
DecoderControl *dc = &(getPlayerData()->decoderControl);
|
||||||
|
|
||||||
pc->cycleLogFiles = 1;
|
pc->cycleLogFiles = 1;
|
||||||
dc->cycleLogFiles = 1;
|
dc->cycleLogFiles = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this actually creates a dupe of the current metadata */
|
/* this actually creates a dupe of the current metadata */
|
||||||
Song * playerCurrentDecodeSong() {
|
Song *playerCurrentDecodeSong()
|
||||||
static Song * song = NULL;
|
{
|
||||||
static MetadataChunk * prev = NULL;
|
static Song *song = NULL;
|
||||||
Song * ret = NULL;
|
static MetadataChunk *prev = NULL;
|
||||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
Song *ret = NULL;
|
||||||
|
PlayerControl *pc = &(getPlayerData()->playerControl);
|
||||||
|
|
||||||
if(pc->metadataState == PLAYER_METADATA_STATE_READ) {
|
if (pc->metadataState == PLAYER_METADATA_STATE_READ) {
|
||||||
DEBUG("playerCurrentDecodeSong: caught new metadata!\n");
|
DEBUG("playerCurrentDecodeSong: caught new metadata!\n");
|
||||||
if(prev) free(prev);
|
if (prev)
|
||||||
|
free(prev);
|
||||||
prev = malloc(sizeof(MetadataChunk));
|
prev = malloc(sizeof(MetadataChunk));
|
||||||
memcpy(prev, &(pc->metadataChunk), sizeof(MetadataChunk));
|
memcpy(prev, &(pc->metadataChunk), sizeof(MetadataChunk));
|
||||||
if(song) freeJustSong(song);
|
if (song)
|
||||||
|
freeJustSong(song);
|
||||||
song = newNullSong();
|
song = newNullSong();
|
||||||
song->url = strdup(pc->currentUrl);
|
song->url = strdup(pc->currentUrl);
|
||||||
song->tag = metadataChunkToMpdTagDup(prev);
|
song->tag = metadataChunkToMpdTagDup(prev);
|
||||||
|
10
src/player.h
10
src/player.h
@ -70,9 +70,9 @@ typedef struct _PlayerControl {
|
|||||||
volatile float totalTime;
|
volatile float totalTime;
|
||||||
volatile float elapsedTime;
|
volatile float elapsedTime;
|
||||||
volatile float fileTime;
|
volatile float fileTime;
|
||||||
char utf8url[MAXPATHLEN+1];
|
char utf8url[MAXPATHLEN + 1];
|
||||||
char currentUrl[MAXPATHLEN+1];
|
char currentUrl[MAXPATHLEN + 1];
|
||||||
char erroredUrl[MAXPATHLEN+1];
|
char erroredUrl[MAXPATHLEN + 1];
|
||||||
volatile mpd_sint8 queueState;
|
volatile mpd_sint8 queueState;
|
||||||
volatile mpd_sint8 queueLockState;
|
volatile mpd_sint8 queueLockState;
|
||||||
volatile mpd_sint8 lockQueue;
|
volatile mpd_sint8 lockQueue;
|
||||||
@ -115,7 +115,7 @@ int getPlayerState();
|
|||||||
|
|
||||||
void clearPlayerError();
|
void clearPlayerError();
|
||||||
|
|
||||||
char * getPlayerErrorStr();
|
char *getPlayerErrorStr();
|
||||||
|
|
||||||
int getPlayerError();
|
int getPlayerError();
|
||||||
|
|
||||||
@ -149,6 +149,6 @@ int getPlayerChannels();
|
|||||||
|
|
||||||
void playerCycleLogFiles();
|
void playerCycleLogFiles();
|
||||||
|
|
||||||
Song * playerCurrentDecodeSong();
|
Song *playerCurrentDecodeSong();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
101
src/playerData.c
101
src/playerData.c
@ -33,44 +33,45 @@ int buffered_chunks;
|
|||||||
#define DEFAULT_BUFFER_SIZE 2048
|
#define DEFAULT_BUFFER_SIZE 2048
|
||||||
#define DEFAULT_BUFFER_BEFORE_PLAY 0
|
#define DEFAULT_BUFFER_BEFORE_PLAY 0
|
||||||
|
|
||||||
static PlayerData * playerData_pd;
|
static PlayerData *playerData_pd;
|
||||||
int * player_pid;
|
int *player_pid;
|
||||||
|
|
||||||
void initPlayerData(void) {
|
void initPlayerData(void)
|
||||||
|
{
|
||||||
float perc = DEFAULT_BUFFER_BEFORE_PLAY;
|
float perc = DEFAULT_BUFFER_BEFORE_PLAY;
|
||||||
char * test;
|
char *test;
|
||||||
int shmid;
|
int shmid;
|
||||||
int crossfade = 0;
|
int crossfade = 0;
|
||||||
size_t bufferSize = DEFAULT_BUFFER_SIZE;
|
size_t bufferSize = DEFAULT_BUFFER_SIZE;
|
||||||
size_t allocationSize;
|
size_t allocationSize;
|
||||||
OutputBuffer * buffer;
|
OutputBuffer *buffer;
|
||||||
ConfigParam * param;
|
ConfigParam *param;
|
||||||
|
|
||||||
param = getConfigParam(CONF_AUDIO_BUFFER_SIZE);
|
param = getConfigParam(CONF_AUDIO_BUFFER_SIZE);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
bufferSize = strtol(param->value, &test, 10);
|
bufferSize = strtol(param->value, &test, 10);
|
||||||
if(*test!='\0' || bufferSize<=0) {
|
if (*test != '\0' || bufferSize <= 0) {
|
||||||
ERROR("buffer size \"%s\" is not a positive integer, "
|
ERROR("buffer size \"%s\" is not a positive integer, "
|
||||||
"line %i\n", param->value, param->line);
|
"line %i\n", param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferSize*=1024;
|
bufferSize *= 1024;
|
||||||
|
|
||||||
buffered_chunks = bufferSize/CHUNK_SIZE;
|
buffered_chunks = bufferSize / CHUNK_SIZE;
|
||||||
|
|
||||||
if(buffered_chunks >= 1<<15) {
|
if (buffered_chunks >= 1 << 15) {
|
||||||
ERROR("buffer size \"%i\" is too big\n",bufferSize);
|
ERROR("buffer size \"%i\" is too big\n", bufferSize);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
param = getConfigParam(CONF_BUFFER_BEFORE_PLAY);
|
param = getConfigParam(CONF_BUFFER_BEFORE_PLAY);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
perc = strtod(param->value, &test);
|
perc = strtod(param->value, &test);
|
||||||
if(*test!='%' || perc<0 || perc>100) {
|
if (*test != '%' || perc < 0 || perc > 100) {
|
||||||
ERROR("buffered before play \"%s\" is not a positive "
|
ERROR("buffered before play \"%s\" is not a positive "
|
||||||
"percentage and less than 100 percent, line %i"
|
"percentage and less than 100 percent, line %i"
|
||||||
"\n", param->value, param->line);
|
"\n", param->value, param->line);
|
||||||
@ -78,28 +79,28 @@ void initPlayerData(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buffered_before_play = (perc/100)*buffered_chunks;
|
buffered_before_play = (perc / 100) * buffered_chunks;
|
||||||
if(buffered_before_play>buffered_chunks) {
|
if (buffered_before_play > buffered_chunks) {
|
||||||
buffered_before_play = buffered_chunks;
|
buffered_before_play = buffered_chunks;
|
||||||
}
|
} else if (buffered_before_play < 0)
|
||||||
else if(buffered_before_play<0) buffered_before_play = 0;
|
buffered_before_play = 0;
|
||||||
|
|
||||||
allocationSize = buffered_chunks*CHUNK_SIZE; /*actual buffer*/
|
allocationSize = buffered_chunks * CHUNK_SIZE; /*actual buffer */
|
||||||
allocationSize+= buffered_chunks*sizeof(float); /*for times*/
|
allocationSize += buffered_chunks * sizeof(float); /*for times */
|
||||||
allocationSize+= buffered_chunks*sizeof(mpd_sint16); /*for chunkSize*/
|
allocationSize += buffered_chunks * sizeof(mpd_sint16); /*for chunkSize */
|
||||||
allocationSize+= buffered_chunks*sizeof(mpd_sint16); /*for bitRate*/
|
allocationSize += buffered_chunks * sizeof(mpd_sint16); /*for bitRate */
|
||||||
allocationSize+= buffered_chunks*sizeof(mpd_sint8); /*for metaChunk*/
|
allocationSize += buffered_chunks * sizeof(mpd_sint8); /*for metaChunk */
|
||||||
allocationSize+= sizeof(PlayerData); /*for playerData struct*/
|
allocationSize += sizeof(PlayerData); /*for playerData struct */
|
||||||
|
|
||||||
if((shmid = shmget(IPC_PRIVATE,allocationSize,IPC_CREAT|0600))<0) {
|
if ((shmid = shmget(IPC_PRIVATE, allocationSize, IPC_CREAT | 0600)) < 0) {
|
||||||
ERROR("problems shmget'ing\n");
|
ERROR("problems shmget'ing\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if((playerData_pd = shmat(shmid,NULL,0))<0) {
|
if ((playerData_pd = shmat(shmid, NULL, 0)) < 0) {
|
||||||
ERROR("problems shmat'ing\n");
|
ERROR("problems shmat'ing\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (shmctl(shmid, IPC_RMID, NULL)<0) {
|
if (shmctl(shmid, IPC_RMID, NULL) < 0) {
|
||||||
ERROR("problems shmctl'ing\n");
|
ERROR("problems shmctl'ing\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -107,30 +108,32 @@ void initPlayerData(void) {
|
|||||||
* or maybe even made a part of the playerData struct
|
* or maybe even made a part of the playerData struct
|
||||||
*/
|
*/
|
||||||
allocationSize = sizeof(int);
|
allocationSize = sizeof(int);
|
||||||
if((shmid = shmget(IPC_PRIVATE,allocationSize,IPC_CREAT|0600))<0) {
|
if ((shmid = shmget(IPC_PRIVATE, allocationSize, IPC_CREAT | 0600)) < 0) {
|
||||||
ERROR("problems shmget'ing\n");
|
ERROR("problems shmget'ing\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if((player_pid = shmat(shmid,NULL,0))<0) {
|
if ((player_pid = shmat(shmid, NULL, 0)) < 0) {
|
||||||
ERROR("problems shmat'ing\n");
|
ERROR("problems shmat'ing\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if (shmctl(shmid, IPC_RMID, NULL)<0) {
|
if (shmctl(shmid, IPC_RMID, NULL) < 0) {
|
||||||
ERROR("problems shmctl'ing\n");
|
ERROR("problems shmctl'ing\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer = &(playerData_pd->buffer);
|
buffer = &(playerData_pd->buffer);
|
||||||
|
|
||||||
buffer->chunks = ((char *)playerData_pd)+sizeof(PlayerData);
|
buffer->chunks = ((char *)playerData_pd) + sizeof(PlayerData);
|
||||||
buffer->chunkSize = (mpd_uint16 *)(((char *)buffer->chunks)+
|
buffer->chunkSize = (mpd_uint16 *) (((char *)buffer->chunks) +
|
||||||
buffered_chunks*CHUNK_SIZE);
|
buffered_chunks * CHUNK_SIZE);
|
||||||
buffer->bitRate = (mpd_uint16 *)(((char *)buffer->chunkSize)+
|
buffer->bitRate = (mpd_uint16 *) (((char *)buffer->chunkSize) +
|
||||||
buffered_chunks*sizeof(mpd_sint16));
|
buffered_chunks * sizeof(mpd_sint16));
|
||||||
buffer->metaChunk = (mpd_sint8 *)(((char *)buffer->bitRate)+
|
buffer->metaChunk = (mpd_sint8 *) (((char *)buffer->bitRate) +
|
||||||
buffered_chunks*sizeof(mpd_sint16));
|
buffered_chunks *
|
||||||
buffer->times = (float *)(((char *)buffer->metaChunk)+
|
sizeof(mpd_sint16));
|
||||||
buffered_chunks*sizeof(mpd_sint8));
|
buffer->times =
|
||||||
|
(float *)(((char *)buffer->metaChunk) +
|
||||||
|
buffered_chunks * sizeof(mpd_sint8));
|
||||||
buffer->acceptMetadata = 0;
|
buffer->acceptMetadata = 0;
|
||||||
|
|
||||||
playerData_pd->playerControl.stop = 0;
|
playerData_pd->playerControl.stop = 0;
|
||||||
@ -144,9 +147,9 @@ void initPlayerData(void) {
|
|||||||
playerData_pd->playerControl.queueLockState = PLAYER_QUEUE_UNLOCKED;
|
playerData_pd->playerControl.queueLockState = PLAYER_QUEUE_UNLOCKED;
|
||||||
playerData_pd->playerControl.seek = 0;
|
playerData_pd->playerControl.seek = 0;
|
||||||
playerData_pd->playerControl.closeAudio = 0;
|
playerData_pd->playerControl.closeAudio = 0;
|
||||||
memset(playerData_pd->playerControl.utf8url, 0, MAXPATHLEN+1);
|
memset(playerData_pd->playerControl.utf8url, 0, MAXPATHLEN + 1);
|
||||||
memset(playerData_pd->playerControl.erroredUrl, 0, MAXPATHLEN+1);
|
memset(playerData_pd->playerControl.erroredUrl, 0, MAXPATHLEN + 1);
|
||||||
memset(playerData_pd->playerControl.currentUrl, 0, MAXPATHLEN+1);
|
memset(playerData_pd->playerControl.currentUrl, 0, MAXPATHLEN + 1);
|
||||||
playerData_pd->playerControl.crossFade = crossfade;
|
playerData_pd->playerControl.crossFade = crossfade;
|
||||||
playerData_pd->playerControl.softwareVolume = 1000;
|
playerData_pd->playerControl.softwareVolume = 1000;
|
||||||
playerData_pd->playerControl.totalPlayTime = 0;
|
playerData_pd->playerControl.totalPlayTime = 0;
|
||||||
@ -159,22 +162,26 @@ void initPlayerData(void) {
|
|||||||
playerData_pd->decoderControl.state = DECODE_STATE_STOP;
|
playerData_pd->decoderControl.state = DECODE_STATE_STOP;
|
||||||
playerData_pd->decoderControl.seek = 0;
|
playerData_pd->decoderControl.seek = 0;
|
||||||
playerData_pd->decoderControl.error = DECODE_ERROR_NOERROR;
|
playerData_pd->decoderControl.error = DECODE_ERROR_NOERROR;
|
||||||
memset(playerData_pd->decoderControl.utf8url, 0, MAXPATHLEN+1);
|
memset(playerData_pd->decoderControl.utf8url, 0, MAXPATHLEN + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerData * getPlayerData(void) {
|
PlayerData *getPlayerData(void)
|
||||||
|
{
|
||||||
return playerData_pd;
|
return playerData_pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPlayerPid(void) {
|
int getPlayerPid(void)
|
||||||
|
{
|
||||||
return *player_pid;
|
return *player_pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPlayerPid(int pid) {
|
void setPlayerPid(int pid)
|
||||||
|
{
|
||||||
*player_pid = pid;
|
*player_pid = pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freePlayerData(void) {
|
void freePlayerData(void)
|
||||||
|
{
|
||||||
shmdt(playerData_pd);
|
shmdt(playerData_pd);
|
||||||
shmdt(player_pid);
|
shmdt(player_pid);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ typedef struct _PlayerData {
|
|||||||
|
|
||||||
void initPlayerData();
|
void initPlayerData();
|
||||||
|
|
||||||
PlayerData * getPlayerData();
|
PlayerData *getPlayerData();
|
||||||
int getPlayerPid();
|
int getPlayerPid();
|
||||||
void setPlayerPid(int pid);
|
void setPlayerPid(int pid);
|
||||||
|
|
||||||
|
1176
src/playlist.c
1176
src/playlist.c
File diff suppressed because it is too large
Load Diff
@ -40,7 +40,7 @@ void savePlaylistState();
|
|||||||
|
|
||||||
int clearPlaylist(FILE * fp);
|
int clearPlaylist(FILE * fp);
|
||||||
|
|
||||||
int addToPlaylist(FILE * fp, char * file, int printId);
|
int addToPlaylist(FILE * fp, char *file, int printId);
|
||||||
|
|
||||||
int addSongToPlaylist(FILE * fp, Song * song, int printId);
|
int addSongToPlaylist(FILE * fp, Song * song, int printId);
|
||||||
|
|
||||||
@ -68,11 +68,11 @@ int previousSongInPlaylist(FILE * fp);
|
|||||||
|
|
||||||
int shufflePlaylist(FILE * fp);
|
int shufflePlaylist(FILE * fp);
|
||||||
|
|
||||||
int savePlaylist(FILE * fp, char * utf8file);
|
int savePlaylist(FILE * fp, char *utf8file);
|
||||||
|
|
||||||
int deletePlaylist(FILE * fp, char * utf8file);
|
int deletePlaylist(FILE * fp, char *utf8file);
|
||||||
|
|
||||||
int deletePlaylistById(FILE * fp, char * utf8file);
|
int deletePlaylistById(FILE * fp, char *utf8file);
|
||||||
|
|
||||||
void deleteASongFromPlaylist(Song * song);
|
void deleteASongFromPlaylist(Song * song);
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ int swapSongsInPlaylist(FILE * fp, int song1, int song2);
|
|||||||
|
|
||||||
int swapSongsInPlaylistById(FILE * fp, int id1, int id2);
|
int swapSongsInPlaylistById(FILE * fp, int id1, int id2);
|
||||||
|
|
||||||
int loadPlaylist(FILE * fp, char * utf8file);
|
int loadPlaylist(FILE * fp, char *utf8file);
|
||||||
|
|
||||||
int getPlaylistRepeatStatus();
|
int getPlaylistRepeatStatus();
|
||||||
|
|
||||||
@ -114,8 +114,8 @@ int playlistChanges(FILE * fp, mpd_uint32 version);
|
|||||||
|
|
||||||
int playlistChangesPosId(FILE * fp, mpd_uint32 version);
|
int playlistChangesPosId(FILE * fp, mpd_uint32 version);
|
||||||
|
|
||||||
int PlaylistInfo(FILE * fp, char * utf8file, int detail);
|
int PlaylistInfo(FILE * fp, char *utf8file, int detail);
|
||||||
|
|
||||||
char * getStateFile();
|
char *getStateFile();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,18 +31,18 @@ static int replayGainState = REPLAYGAIN_OFF;
|
|||||||
|
|
||||||
static float replayGainPreamp = 1.0;
|
static float replayGainPreamp = 1.0;
|
||||||
|
|
||||||
void initReplayGainState(void) {
|
void initReplayGainState(void)
|
||||||
ConfigParam * param = getConfigParam(CONF_REPLAYGAIN);
|
{
|
||||||
|
ConfigParam *param = getConfigParam(CONF_REPLAYGAIN);
|
||||||
|
|
||||||
if(!param) return;
|
if (!param)
|
||||||
|
return;
|
||||||
|
|
||||||
if(strcmp(param->value, "track") == 0) {
|
if (strcmp(param->value, "track") == 0) {
|
||||||
replayGainState = REPLAYGAIN_TRACK;
|
replayGainState = REPLAYGAIN_TRACK;
|
||||||
}
|
} else if (strcmp(param->value, "album") == 0) {
|
||||||
else if(strcmp(param->value, "album") == 0) {
|
|
||||||
replayGainState = REPLAYGAIN_ALBUM;
|
replayGainState = REPLAYGAIN_ALBUM;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ERROR("replaygain value \"%s\" at line %i is invalid\n",
|
ERROR("replaygain value \"%s\" at line %i is invalid\n",
|
||||||
param->value, param->line);
|
param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -50,43 +50,46 @@ void initReplayGainState(void) {
|
|||||||
|
|
||||||
param = getConfigParam(CONF_REPLAYGAIN_PREAMP);
|
param = getConfigParam(CONF_REPLAYGAIN_PREAMP);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
char * test;
|
char *test;
|
||||||
float f = strtod(param->value, &test);
|
float f = strtod(param->value, &test);
|
||||||
|
|
||||||
if(*test != '\0') {
|
if (*test != '\0') {
|
||||||
ERROR("Replaygain preamp \"%s\" is not a number at "
|
ERROR("Replaygain preamp \"%s\" is not a number at "
|
||||||
"line %i\n", param->value, param->line);
|
"line %i\n", param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(f < -15 || f > 15) {
|
if (f < -15 || f > 15) {
|
||||||
ERROR("Replaygain preamp \"%s\" is not between -15 and"
|
ERROR("Replaygain preamp \"%s\" is not between -15 and"
|
||||||
"15 at line %i\n",
|
"15 at line %i\n", param->value, param->line);
|
||||||
param->value, param->line);
|
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
replayGainPreamp = pow(10, f/20.0);
|
replayGainPreamp = pow(10, f / 20.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static float computeReplayGainScale(float gain, float peak) {
|
static float computeReplayGainScale(float gain, float peak)
|
||||||
|
{
|
||||||
float scale;
|
float scale;
|
||||||
|
|
||||||
if(gain == 0.0) return(1);
|
if (gain == 0.0)
|
||||||
scale = pow(10.0, gain/20.0);
|
return (1);
|
||||||
scale*= replayGainPreamp;
|
scale = pow(10.0, gain / 20.0);
|
||||||
if(scale > 15.0) scale = 15.0;
|
scale *= replayGainPreamp;
|
||||||
|
if (scale > 15.0)
|
||||||
|
scale = 15.0;
|
||||||
|
|
||||||
if (scale * peak > 1.0) {
|
if (scale * peak > 1.0) {
|
||||||
scale = 1.0 / peak;
|
scale = 1.0 / peak;
|
||||||
}
|
}
|
||||||
return(scale);
|
return (scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplayGainInfo * newReplayGainInfo(void) {
|
ReplayGainInfo *newReplayGainInfo(void)
|
||||||
ReplayGainInfo * ret = malloc(sizeof(ReplayGainInfo));
|
{
|
||||||
|
ReplayGainInfo *ret = malloc(sizeof(ReplayGainInfo));
|
||||||
|
|
||||||
ret->albumGain = 0.0;
|
ret->albumGain = 0.0;
|
||||||
ret->albumPeak = 0.0;
|
ret->albumPeak = 0.0;
|
||||||
@ -100,22 +103,24 @@ ReplayGainInfo * newReplayGainInfo(void) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeReplayGainInfo(ReplayGainInfo * info) {
|
void freeReplayGainInfo(ReplayGainInfo * info)
|
||||||
|
{
|
||||||
free(info);
|
free(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize,
|
void doReplayGain(ReplayGainInfo * info, char *buffer, int bufferSize,
|
||||||
AudioFormat * format)
|
AudioFormat * format)
|
||||||
{
|
{
|
||||||
mpd_sint16 * buffer16;
|
mpd_sint16 *buffer16;
|
||||||
mpd_sint8 * buffer8;
|
mpd_sint8 *buffer8;
|
||||||
mpd_sint32 temp32;
|
mpd_sint32 temp32;
|
||||||
float scale;
|
float scale;
|
||||||
|
|
||||||
if(replayGainState == REPLAYGAIN_OFF || !info) return;
|
if (replayGainState == REPLAYGAIN_OFF || !info)
|
||||||
|
return;
|
||||||
|
|
||||||
if(info->scale < 0) {
|
if (info->scale < 0) {
|
||||||
switch(replayGainState) {
|
switch (replayGainState) {
|
||||||
case REPLAYGAIN_TRACK:
|
case REPLAYGAIN_TRACK:
|
||||||
info->scale = computeReplayGainScale(info->trackGain,
|
info->scale = computeReplayGainScale(info->trackGain,
|
||||||
info->trackPeak);
|
info->trackPeak);
|
||||||
@ -127,30 +132,31 @@ void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(info->scale <= 1.01 && info->scale >= 0.99) return;
|
if (info->scale <= 1.01 && info->scale >= 0.99)
|
||||||
|
return;
|
||||||
|
|
||||||
buffer16 = (mpd_sint16 *)buffer;
|
buffer16 = (mpd_sint16 *) buffer;
|
||||||
buffer8 = (mpd_sint8 *)buffer;
|
buffer8 = (mpd_sint8 *) buffer;
|
||||||
|
|
||||||
scale = info->scale;
|
scale = info->scale;
|
||||||
|
|
||||||
switch(format->bits) {
|
switch (format->bits) {
|
||||||
case 16:
|
case 16:
|
||||||
while(bufferSize > 0){
|
while (bufferSize > 0) {
|
||||||
temp32 = *buffer16;
|
temp32 = *buffer16;
|
||||||
temp32 *= scale;
|
temp32 *= scale;
|
||||||
*buffer16 = temp32>32767 ? 32767 :
|
*buffer16 = temp32 > 32767 ? 32767 :
|
||||||
(temp32<-32768 ? -32768 : temp32);
|
(temp32 < -32768 ? -32768 : temp32);
|
||||||
buffer16++;
|
buffer16++;
|
||||||
bufferSize-=2;
|
bufferSize -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
while(bufferSize>0){
|
while (bufferSize > 0) {
|
||||||
temp32 = *buffer8;
|
temp32 = *buffer8;
|
||||||
temp32 *= scale;
|
temp32 *= scale;
|
||||||
*buffer8 = temp32>127 ? 127 :
|
*buffer8 = temp32 > 127 ? 127 :
|
||||||
(temp32<-128 ? -128 : temp32);
|
(temp32 < -128 ? -128 : temp32);
|
||||||
buffer8++;
|
buffer8++;
|
||||||
bufferSize--;
|
bufferSize--;
|
||||||
}
|
}
|
||||||
|
@ -32,17 +32,17 @@ typedef struct _ReplayGainInfo {
|
|||||||
float trackGain;
|
float trackGain;
|
||||||
float trackPeak;
|
float trackPeak;
|
||||||
|
|
||||||
/* used internally by mpd, to mess with it*/
|
/* used internally by mpd, to mess with it */
|
||||||
float scale;
|
float scale;
|
||||||
} ReplayGainInfo;
|
} ReplayGainInfo;
|
||||||
|
|
||||||
ReplayGainInfo * newReplayGainInfo();
|
ReplayGainInfo *newReplayGainInfo();
|
||||||
|
|
||||||
void freeReplayGainInfo(ReplayGainInfo * info);
|
void freeReplayGainInfo(ReplayGainInfo * info);
|
||||||
|
|
||||||
void initReplayGainState();
|
void initReplayGainState();
|
||||||
|
|
||||||
void doReplayGain(ReplayGainInfo * info, char * buffer, int bufferSize,
|
void doReplayGain(ReplayGainInfo * info, char *buffer, int bufferSize,
|
||||||
AudioFormat * format);
|
AudioFormat * format);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -39,23 +39,24 @@
|
|||||||
extern volatile int masterPid;
|
extern volatile int masterPid;
|
||||||
extern volatile int mainPid;
|
extern volatile int mainPid;
|
||||||
|
|
||||||
int masterHandlePendingSignals() {
|
int masterHandlePendingSignals()
|
||||||
if(signal_is_pending(SIGINT) || signal_is_pending(SIGTERM)) {
|
{
|
||||||
|
if (signal_is_pending(SIGINT) || signal_is_pending(SIGTERM)) {
|
||||||
DEBUG("master process got SIGINT or SIGTERM, exiting\n");
|
DEBUG("master process got SIGINT or SIGTERM, exiting\n");
|
||||||
return COMMAND_RETURN_KILL;
|
return COMMAND_RETURN_KILL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(signal_is_pending(SIGHUP)) {
|
if (signal_is_pending(SIGHUP)) {
|
||||||
signal_clear(SIGHUP);
|
signal_clear(SIGHUP);
|
||||||
/* Forward it to the main process, which will update the DB */
|
/* Forward it to the main process, which will update the DB */
|
||||||
kill(mainPid, SIGHUP);
|
kill(mainPid, SIGHUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int handlePendingSignals() {
|
int handlePendingSignals()
|
||||||
|
{
|
||||||
/* this SIGUSR1 signal comes before the KILL signals, because there if the process is
|
/* this SIGUSR1 signal comes before the KILL signals, because there if the process is
|
||||||
* looping, waiting for this signal, it will not respond to the KILL signal. This might be
|
* looping, waiting for this signal, it will not respond to the KILL signal. This might be
|
||||||
* better implemented by using bit-wise defines and or'ing of the COMMAND_FOO as return.
|
* better implemented by using bit-wise defines and or'ing of the COMMAND_FOO as return.
|
||||||
@ -66,87 +67,98 @@ int handlePendingSignals() {
|
|||||||
return COMMAND_MASTER_READY;
|
return COMMAND_MASTER_READY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(signal_is_pending(SIGINT) || signal_is_pending(SIGTERM)) {
|
if (signal_is_pending(SIGINT) || signal_is_pending(SIGTERM)) {
|
||||||
DEBUG("main process got SIGINT or SIGTERM, exiting\n");
|
DEBUG("main process got SIGINT or SIGTERM, exiting\n");
|
||||||
return COMMAND_RETURN_KILL;
|
return COMMAND_RETURN_KILL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(signal_is_pending(SIGHUP)) {
|
if (signal_is_pending(SIGHUP)) {
|
||||||
DEBUG("got SIGHUP, rereading DB\n");
|
DEBUG("got SIGHUP, rereading DB\n");
|
||||||
signal_clear(SIGHUP);
|
signal_clear(SIGHUP);
|
||||||
if(!isUpdatingDB()) {
|
if (!isUpdatingDB()) {
|
||||||
readDirectoryDB();
|
readDirectoryDB();
|
||||||
playlistVersionChange();
|
playlistVersionChange();
|
||||||
}
|
}
|
||||||
if(myfprintfCloseAndOpenLogFile()<0) return COMMAND_RETURN_KILL;
|
if (myfprintfCloseAndOpenLogFile() < 0)
|
||||||
|
return COMMAND_RETURN_KILL;
|
||||||
playerCycleLogFiles();
|
playerCycleLogFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void chldSigHandler(int signal) {
|
void chldSigHandler(int signal)
|
||||||
|
{
|
||||||
int status;
|
int status;
|
||||||
int pid;
|
int pid;
|
||||||
DEBUG("main process got SIGCHLD\n");
|
DEBUG("main process got SIGCHLD\n");
|
||||||
while(0 != (pid = wait3(&status,WNOHANG,NULL))) {
|
while (0 != (pid = wait3(&status, WNOHANG, NULL))) {
|
||||||
if(pid<0) {
|
if (pid < 0) {
|
||||||
if(errno==EINTR) continue;
|
if (errno == EINTR)
|
||||||
else break;
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
directory_sigChldHandler(pid,status);
|
directory_sigChldHandler(pid, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void masterChldSigHandler(int signal) {
|
void masterChldSigHandler(int signal)
|
||||||
|
{
|
||||||
int status;
|
int status;
|
||||||
int pid;
|
int pid;
|
||||||
DEBUG("master process got SIGCHLD\n");
|
DEBUG("master process got SIGCHLD\n");
|
||||||
while(0 != (pid = wait3(&status,WNOHANG,NULL))) {
|
while (0 != (pid = wait3(&status, WNOHANG, NULL))) {
|
||||||
if(pid<0) {
|
if (pid < 0) {
|
||||||
if(errno==EINTR) continue;
|
if (errno == EINTR)
|
||||||
else break;
|
continue;
|
||||||
|
else
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
DEBUG("PID: %d\n",pid);
|
DEBUG("PID: %d\n", pid);
|
||||||
if (pid == mainPid) kill(getpid(), SIGTERM);
|
if (pid == mainPid)
|
||||||
player_sigChldHandler(pid,status);
|
kill(getpid(), SIGTERM);
|
||||||
|
player_sigChldHandler(pid, status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int playerInitReal();
|
int playerInitReal();
|
||||||
|
|
||||||
void masterSigUsr2Handler(int signal) {
|
void masterSigUsr2Handler(int signal)
|
||||||
|
{
|
||||||
DEBUG("Master process got SIGUSR2 starting a new player process\n");
|
DEBUG("Master process got SIGUSR2 starting a new player process\n");
|
||||||
if (getPlayerPid() <= 0)
|
if (getPlayerPid() <= 0)
|
||||||
playerInitReal();
|
playerInitReal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void masterInitSigHandlers() {
|
void masterInitSigHandlers()
|
||||||
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
sa.sa_flags = 0;
|
sa.sa_flags = 0;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
while(sigaction(SIGPIPE,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGPIPE, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
sa.sa_handler = masterChldSigHandler;
|
sa.sa_handler = masterChldSigHandler;
|
||||||
while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGCHLD, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
sa.sa_handler = masterSigUsr2Handler;
|
sa.sa_handler = masterSigUsr2Handler;
|
||||||
while(sigaction(SIGUSR2,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGUSR2, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
signal_handle(SIGUSR1);
|
signal_handle(SIGUSR1);
|
||||||
signal_handle(SIGINT);
|
signal_handle(SIGINT);
|
||||||
signal_handle(SIGTERM);
|
signal_handle(SIGTERM);
|
||||||
signal_handle(SIGHUP);
|
signal_handle(SIGHUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initSigHandlers() {
|
void initSigHandlers()
|
||||||
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
sa.sa_flags = 0;
|
sa.sa_flags = 0;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
while(sigaction(SIGPIPE,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGPIPE, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
sa.sa_handler = chldSigHandler;
|
sa.sa_handler = chldSigHandler;
|
||||||
while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGCHLD, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
signal_handle(SIGUSR2);
|
signal_handle(SIGUSR2);
|
||||||
signal_handle(SIGUSR1);
|
signal_handle(SIGUSR1);
|
||||||
signal_handle(SIGINT);
|
signal_handle(SIGINT);
|
||||||
@ -154,14 +166,16 @@ void initSigHandlers() {
|
|||||||
signal_handle(SIGHUP);
|
signal_handle(SIGHUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishSigHandlers() {
|
void finishSigHandlers()
|
||||||
|
{
|
||||||
signal_unhandle(SIGINT);
|
signal_unhandle(SIGINT);
|
||||||
signal_unhandle(SIGUSR1);
|
signal_unhandle(SIGUSR1);
|
||||||
signal_unhandle(SIGTERM);
|
signal_unhandle(SIGTERM);
|
||||||
signal_unhandle(SIGHUP);
|
signal_unhandle(SIGHUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSigHandlersForDecoder() {
|
void setSigHandlersForDecoder()
|
||||||
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
finishSigHandlers();
|
finishSigHandlers();
|
||||||
@ -169,65 +183,69 @@ void setSigHandlersForDecoder() {
|
|||||||
sa.sa_flags = 0;
|
sa.sa_flags = 0;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
while(sigaction(SIGHUP,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGHUP, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
while(sigaction(SIGINT,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGINT, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
sa.sa_flags = SA_SIGINFO;
|
sa.sa_flags = SA_SIGINFO;
|
||||||
sa.sa_sigaction = decodeSigHandler;
|
sa.sa_sigaction = decodeSigHandler;
|
||||||
while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGCHLD, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
while(sigaction(SIGTERM,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGTERM, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ignoreSignals() {
|
void ignoreSignals()
|
||||||
|
{
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
sa.sa_flags = 0;
|
sa.sa_flags = 0;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sa.sa_handler = SIG_IGN;
|
sa.sa_handler = SIG_IGN;
|
||||||
sa.sa_sigaction = NULL;
|
sa.sa_sigaction = NULL;
|
||||||
while(sigaction(SIGPIPE,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGPIPE, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGCHLD, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
while(sigaction(SIGUSR1,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGUSR1, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
while(sigaction(SIGUSR2,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGUSR2, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
while(sigaction(SIGINT,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGINT, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
while(sigaction(SIGTERM,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGTERM, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
while(sigaction(SIGHUP,&sa,NULL)<0 && errno==EINTR);
|
while (sigaction(SIGHUP, &sa, NULL) < 0 && errno == EINTR) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
void waitOnSignals() {
|
void waitOnSignals()
|
||||||
|
{
|
||||||
sigset_t sset;
|
sigset_t sset;
|
||||||
|
|
||||||
sigfillset(&sset);
|
sigfillset(&sset);
|
||||||
sigdelset(&sset,SIGCHLD);
|
sigdelset(&sset, SIGCHLD);
|
||||||
sigdelset(&sset,SIGUSR1);
|
sigdelset(&sset, SIGUSR1);
|
||||||
sigdelset(&sset,SIGUSR2);
|
sigdelset(&sset, SIGUSR2);
|
||||||
sigdelset(&sset,SIGHUP);
|
sigdelset(&sset, SIGHUP);
|
||||||
sigdelset(&sset,SIGINT);
|
sigdelset(&sset, SIGINT);
|
||||||
sigdelset(&sset,SIGTERM);
|
sigdelset(&sset, SIGTERM);
|
||||||
sigsuspend(&sset);
|
sigsuspend(&sset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void blockSignals() {
|
void blockSignals()
|
||||||
|
{
|
||||||
sigset_t sset;
|
sigset_t sset;
|
||||||
|
|
||||||
sigemptyset(&sset);
|
sigemptyset(&sset);
|
||||||
sigaddset(&sset,SIGCHLD);
|
sigaddset(&sset, SIGCHLD);
|
||||||
sigaddset(&sset,SIGUSR1);
|
sigaddset(&sset, SIGUSR1);
|
||||||
sigaddset(&sset,SIGUSR2);
|
sigaddset(&sset, SIGUSR2);
|
||||||
sigaddset(&sset,SIGHUP);
|
sigaddset(&sset, SIGHUP);
|
||||||
sigaddset(&sset,SIGINT);
|
sigaddset(&sset, SIGINT);
|
||||||
sigaddset(&sset,SIGTERM);
|
sigaddset(&sset, SIGTERM);
|
||||||
while(sigprocmask(SIG_BLOCK,&sset,NULL)<0 && errno==EINTR);
|
while (sigprocmask(SIG_BLOCK, &sset, NULL) < 0 && errno == EINTR) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unblockSignals() {
|
void unblockSignals()
|
||||||
|
{
|
||||||
sigset_t sset;
|
sigset_t sset;
|
||||||
|
|
||||||
sigemptyset(&sset);
|
sigemptyset(&sset);
|
||||||
sigaddset(&sset,SIGCHLD);
|
sigaddset(&sset, SIGCHLD);
|
||||||
sigaddset(&sset,SIGUSR1);
|
sigaddset(&sset, SIGUSR1);
|
||||||
sigaddset(&sset,SIGUSR2);
|
sigaddset(&sset, SIGUSR2);
|
||||||
sigaddset(&sset,SIGHUP);
|
sigaddset(&sset, SIGHUP);
|
||||||
sigaddset(&sset,SIGINT);
|
sigaddset(&sset, SIGINT);
|
||||||
sigaddset(&sset,SIGTERM);
|
sigaddset(&sset, SIGTERM);
|
||||||
while(sigprocmask(SIG_UNBLOCK,&sset,NULL)<0 && errno==EINTR);
|
while (sigprocmask(SIG_UNBLOCK, &sset, NULL) < 0 && errno == EINTR) ;
|
||||||
}
|
}
|
||||||
|
@ -29,13 +29,13 @@ static void __signal_handler(int sig)
|
|||||||
__caught_signals[sig] = 1;
|
__caught_signals[sig] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __set_signal_handler(int sig, void (* handler)(int))
|
static void __set_signal_handler(int sig, void (*handler) (int))
|
||||||
{
|
{
|
||||||
struct sigaction act;
|
struct sigaction act;
|
||||||
act.sa_flags = 0;
|
act.sa_flags = 0;
|
||||||
sigemptyset(&act.sa_mask);
|
sigemptyset(&act.sa_mask);
|
||||||
act.sa_handler = handler;
|
act.sa_handler = handler;
|
||||||
while(sigaction(sig, &act, NULL) && errno==EINTR);
|
while (sigaction(sig, &act, NULL) && errno == EINTR) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
void signal_handle(int sig)
|
void signal_handle(int sig)
|
||||||
|
267
src/song.c
267
src/song.c
@ -35,8 +35,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
Song * newNullSong(void) {
|
Song *newNullSong(void)
|
||||||
Song * song = malloc(sizeof(Song));
|
{
|
||||||
|
Song *song = malloc(sizeof(Song));
|
||||||
|
|
||||||
song->tag = NULL;
|
song->tag = NULL;
|
||||||
song->url = NULL;
|
song->url = NULL;
|
||||||
@ -46,11 +47,12 @@ Song * newNullSong(void) {
|
|||||||
return song;
|
return song;
|
||||||
}
|
}
|
||||||
|
|
||||||
Song * newSong(char * url, int type, Directory * parentDir) {
|
Song *newSong(char *url, int type, Directory * parentDir)
|
||||||
Song * song = NULL;
|
{
|
||||||
|
Song *song = NULL;
|
||||||
|
|
||||||
if(strchr(url, '\n')) {
|
if (strchr(url, '\n')) {
|
||||||
DEBUG("newSong: '%s' is not a valid uri\n",url);
|
DEBUG("newSong: '%s' is not a valid uri\n", url);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,16 +64,17 @@ Song * newSong(char * url, int type, Directory * parentDir) {
|
|||||||
|
|
||||||
assert(type == SONG_TYPE_URL || parentDir);
|
assert(type == SONG_TYPE_URL || parentDir);
|
||||||
|
|
||||||
if(song->type == SONG_TYPE_FILE) {
|
if (song->type == SONG_TYPE_FILE) {
|
||||||
InputPlugin * plugin;
|
InputPlugin *plugin;
|
||||||
unsigned int next = 0;
|
unsigned int next = 0;
|
||||||
char * song_url = getSongUrl(song);
|
char *song_url = getSongUrl(song);
|
||||||
char * abs_path = rmp2amp(utf8ToFsCharset(song_url));
|
char *abs_path = rmp2amp(utf8ToFsCharset(song_url));
|
||||||
while(!song->tag && (plugin = isMusic(song_url,
|
while (!song->tag && (plugin = isMusic(song_url,
|
||||||
&(song->mtime), next++))) {
|
&(song->mtime),
|
||||||
|
next++))) {
|
||||||
song->tag = plugin->tagDupFunc(abs_path);
|
song->tag = plugin->tagDupFunc(abs_path);
|
||||||
}
|
}
|
||||||
if(!song->tag || song->tag->time<0) {
|
if (!song->tag || song->tag->time < 0) {
|
||||||
freeSong(song);
|
freeSong(song);
|
||||||
song = NULL;
|
song = NULL;
|
||||||
}
|
}
|
||||||
@ -80,30 +83,34 @@ Song * newSong(char * url, int type, Directory * parentDir) {
|
|||||||
return song;
|
return song;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeSong(Song * song) {
|
void freeSong(Song * song)
|
||||||
|
{
|
||||||
deleteASongFromPlaylist(song);
|
deleteASongFromPlaylist(song);
|
||||||
freeJustSong(song);
|
freeJustSong(song);
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeJustSong(Song * song) {
|
void freeJustSong(Song * song)
|
||||||
|
{
|
||||||
free(song->url);
|
free(song->url);
|
||||||
if(song->tag) freeMpdTag(song->tag);
|
if (song->tag)
|
||||||
|
freeMpdTag(song->tag);
|
||||||
free(song);
|
free(song);
|
||||||
getSongUrl(NULL);
|
getSongUrl(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
SongList * newSongList(void) {
|
SongList *newSongList(void)
|
||||||
return makeList((ListFreeDataFunc *)freeSong, 0);
|
{
|
||||||
|
return makeList((ListFreeDataFunc *) freeSong, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Song * addSongToList(SongList * list, char * url, char * utf8path,
|
Song *addSongToList(SongList * list, char *url, char *utf8path,
|
||||||
int songType, Directory * parentDirectory)
|
int songType, Directory * parentDirectory)
|
||||||
{
|
{
|
||||||
Song * song = NULL;
|
Song *song = NULL;
|
||||||
|
|
||||||
switch(songType) {
|
switch (songType) {
|
||||||
case SONG_TYPE_FILE:
|
case SONG_TYPE_FILE:
|
||||||
if(isMusic(utf8path, NULL, 0)) {
|
if (isMusic(utf8path, NULL, 0)) {
|
||||||
song = newSong(url, songType, parentDirectory);
|
song = newSong(url, songType, parentDirectory);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -114,80 +121,86 @@ Song * addSongToList(SongList * list, char * url, char * utf8path,
|
|||||||
DEBUG("addSongToList: Trying to add an invalid song type\n");
|
DEBUG("addSongToList: Trying to add an invalid song type\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(song==NULL) return NULL;
|
if (song == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
insertInList(list, song->url, (void *)song);
|
insertInList(list, song->url, (void *)song);
|
||||||
|
|
||||||
return song;
|
return song;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeSongList(SongList * list) {
|
void freeSongList(SongList * list)
|
||||||
|
{
|
||||||
freeList(list);
|
freeList(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printSongUrl(FILE * fp, Song * song) {
|
void printSongUrl(FILE * fp, Song * song)
|
||||||
if(song->parentDir && song->parentDir->path) {
|
{
|
||||||
|
if (song->parentDir && song->parentDir->path) {
|
||||||
myfprintf(fp, "%s%s/%s\n", SONG_FILE,
|
myfprintf(fp, "%s%s/%s\n", SONG_FILE,
|
||||||
getDirectoryPath(song->parentDir), song->url);
|
getDirectoryPath(song->parentDir), song->url);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
myfprintf(fp, "%s%s\n", SONG_FILE, song->url);
|
myfprintf(fp, "%s%s\n", SONG_FILE, song->url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int printSongInfo(FILE * fp, Song * song) {
|
int printSongInfo(FILE * fp, Song * song)
|
||||||
|
{
|
||||||
printSongUrl(fp, song);
|
printSongUrl(fp, song);
|
||||||
|
|
||||||
if(song->tag) printMpdTag(fp,song->tag);
|
if (song->tag)
|
||||||
|
printMpdTag(fp, song->tag);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int printSongInfoFromList(FILE * fp, SongList * list) {
|
int printSongInfoFromList(FILE * fp, SongList * list)
|
||||||
ListNode * tempNode = list->firstNode;
|
|
||||||
|
|
||||||
while(tempNode!=NULL) {
|
|
||||||
printSongInfo(fp,(Song *)tempNode->data);
|
|
||||||
tempNode = tempNode->nextNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeSongInfoFromList(FILE * fp, SongList * list) {
|
|
||||||
ListNode * tempNode = list->firstNode;
|
|
||||||
|
|
||||||
myfprintf(fp,"%s\n",SONG_BEGIN);
|
|
||||||
|
|
||||||
while(tempNode!=NULL) {
|
|
||||||
myfprintf(fp,"%s%s\n",SONG_KEY,tempNode->key);
|
|
||||||
printSongInfo(fp,(Song *)tempNode->data);
|
|
||||||
myfprintf(fp,"%s%li\n",SONG_MTIME,(long)((Song *)tempNode->data)->mtime);
|
|
||||||
tempNode = tempNode->nextNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
myfprintf(fp,"%s\n",SONG_END);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void insertSongIntoList(SongList * list, ListNode ** nextSongNode, char * key,
|
|
||||||
Song * song)
|
|
||||||
{
|
{
|
||||||
ListNode * nodeTemp;
|
ListNode *tempNode = list->firstNode;
|
||||||
int cmpRet= 0;
|
|
||||||
|
|
||||||
while(*nextSongNode && (cmpRet = strcmp(key,(*nextSongNode)->key)) > 0)
|
while (tempNode != NULL) {
|
||||||
{
|
printSongInfo(fp, (Song *) tempNode->data);
|
||||||
|
tempNode = tempNode->nextNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeSongInfoFromList(FILE * fp, SongList * list)
|
||||||
|
{
|
||||||
|
ListNode *tempNode = list->firstNode;
|
||||||
|
|
||||||
|
myfprintf(fp, "%s\n", SONG_BEGIN);
|
||||||
|
|
||||||
|
while (tempNode != NULL) {
|
||||||
|
myfprintf(fp, "%s%s\n", SONG_KEY, tempNode->key);
|
||||||
|
printSongInfo(fp, (Song *) tempNode->data);
|
||||||
|
myfprintf(fp, "%s%li\n", SONG_MTIME,
|
||||||
|
(long)((Song *) tempNode->data)->mtime);
|
||||||
|
tempNode = tempNode->nextNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
myfprintf(fp, "%s\n", SONG_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insertSongIntoList(SongList * list, ListNode ** nextSongNode,
|
||||||
|
char *key, Song * song)
|
||||||
|
{
|
||||||
|
ListNode *nodeTemp;
|
||||||
|
int cmpRet = 0;
|
||||||
|
|
||||||
|
while (*nextSongNode
|
||||||
|
&& (cmpRet = strcmp(key, (*nextSongNode)->key)) > 0) {
|
||||||
nodeTemp = (*nextSongNode)->nextNode;
|
nodeTemp = (*nextSongNode)->nextNode;
|
||||||
deleteNodeFromList(list,*nextSongNode);
|
deleteNodeFromList(list, *nextSongNode);
|
||||||
*nextSongNode = nodeTemp;
|
*nextSongNode = nodeTemp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!(*nextSongNode)) {
|
if (!(*nextSongNode)) {
|
||||||
insertInList(list, song->url, (void *)song);
|
insertInList(list, song->url, (void *)song);
|
||||||
}
|
} else if (cmpRet == 0) {
|
||||||
else if(cmpRet == 0) {
|
Song *tempSong = (Song *) ((*nextSongNode)->data);
|
||||||
Song * tempSong = (Song *)((*nextSongNode)->data);
|
if (tempSong->mtime != song->mtime) {
|
||||||
if(tempSong->mtime != song->mtime) {
|
|
||||||
freeMpdTag(tempSong->tag);
|
freeMpdTag(tempSong->tag);
|
||||||
tempSong->tag = song->tag;
|
tempSong->tag = song->tag;
|
||||||
tempSong->mtime = song->mtime;
|
tempSong->mtime = song->mtime;
|
||||||
@ -195,20 +208,19 @@ static void insertSongIntoList(SongList * list, ListNode ** nextSongNode, char *
|
|||||||
}
|
}
|
||||||
freeJustSong(song);
|
freeJustSong(song);
|
||||||
*nextSongNode = (*nextSongNode)->nextNode;
|
*nextSongNode = (*nextSongNode)->nextNode;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
insertInListBeforeNode(list, *nextSongNode, -1, song->url,
|
insertInListBeforeNode(list, *nextSongNode, -1, song->url,
|
||||||
(void *)song);
|
(void *)song);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int matchesAnMpdTagItemKey(char * buffer, int * itemType) {
|
static int matchesAnMpdTagItemKey(char *buffer, int *itemType)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
||||||
if( 0 == strncmp(mpdTagItemKeys[i], buffer,
|
if (0 == strncmp(mpdTagItemKeys[i], buffer,
|
||||||
strlen(mpdTagItemKeys[i])))
|
strlen(mpdTagItemKeys[i]))) {
|
||||||
{
|
|
||||||
*itemType = i;
|
*itemType = i;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -217,84 +229,88 @@ static int matchesAnMpdTagItemKey(char * buffer, int * itemType) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void readSongInfoIntoList(FILE * fp, SongList * list, Directory * parentDir) {
|
void readSongInfoIntoList(FILE * fp, SongList * list, Directory * parentDir)
|
||||||
char buffer[MAXPATHLEN+1024];
|
{
|
||||||
int bufferSize = MAXPATHLEN+1024;
|
char buffer[MAXPATHLEN + 1024];
|
||||||
Song * song = NULL;
|
int bufferSize = MAXPATHLEN + 1024;
|
||||||
ListNode * nextSongNode = list->firstNode;
|
Song *song = NULL;
|
||||||
ListNode * nodeTemp;
|
ListNode *nextSongNode = list->firstNode;
|
||||||
|
ListNode *nodeTemp;
|
||||||
int itemType;
|
int itemType;
|
||||||
|
|
||||||
while(myFgets(buffer,bufferSize,fp) && 0!=strcmp(SONG_END,buffer)) {
|
while (myFgets(buffer, bufferSize, fp) && 0 != strcmp(SONG_END, buffer)) {
|
||||||
if(0==strncmp(SONG_KEY,buffer,strlen(SONG_KEY))) {
|
if (0 == strncmp(SONG_KEY, buffer, strlen(SONG_KEY))) {
|
||||||
if(song) {
|
if (song) {
|
||||||
insertSongIntoList(list,&nextSongNode,
|
insertSongIntoList(list, &nextSongNode,
|
||||||
song->url,
|
song->url, song);
|
||||||
song);
|
|
||||||
song = NULL;
|
song = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
song = newNullSong();
|
song = newNullSong();
|
||||||
song->url = strdup(buffer+strlen(SONG_KEY));
|
song->url = strdup(buffer + strlen(SONG_KEY));
|
||||||
song->type = SONG_TYPE_FILE;
|
song->type = SONG_TYPE_FILE;
|
||||||
song->parentDir = parentDir;
|
song->parentDir = parentDir;
|
||||||
}
|
} else if (0 == strncmp(SONG_FILE, buffer, strlen(SONG_FILE))) {
|
||||||
else if(0==strncmp(SONG_FILE,buffer,strlen(SONG_FILE))) {
|
if (!song) {
|
||||||
if(!song) {
|
|
||||||
ERROR("Problems reading song info\n");
|
ERROR("Problems reading song info\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
/* we don't need this info anymore
|
/* we don't need this info anymore
|
||||||
song->url = strdup(&(buffer[strlen(SONG_FILE)]));
|
song->url = strdup(&(buffer[strlen(SONG_FILE)]));
|
||||||
*/
|
*/
|
||||||
}
|
} else if (matchesAnMpdTagItemKey(buffer, &itemType)) {
|
||||||
else if(matchesAnMpdTagItemKey(buffer, &itemType)) {
|
if (!song->tag)
|
||||||
if(!song->tag) song->tag = newMpdTag();
|
song->tag = newMpdTag();
|
||||||
addItemToMpdTag(song->tag, itemType,
|
addItemToMpdTag(song->tag, itemType,
|
||||||
&(buffer[strlen(mpdTagItemKeys[itemType])+2]));
|
&(buffer
|
||||||
}
|
[strlen(mpdTagItemKeys[itemType]) +
|
||||||
else if(0==strncmp(SONG_TIME,buffer,strlen(SONG_TIME))) {
|
2]));
|
||||||
if(!song->tag) song->tag = newMpdTag();
|
} else if (0 == strncmp(SONG_TIME, buffer, strlen(SONG_TIME))) {
|
||||||
|
if (!song->tag)
|
||||||
|
song->tag = newMpdTag();
|
||||||
song->tag->time = atoi(&(buffer[strlen(SONG_TIME)]));
|
song->tag->time = atoi(&(buffer[strlen(SONG_TIME)]));
|
||||||
}
|
} else if (0 == strncmp(SONG_MTIME, buffer, strlen(SONG_MTIME))) {
|
||||||
else if(0==strncmp(SONG_MTIME,buffer,strlen(SONG_MTIME))) {
|
|
||||||
song->mtime = atoi(&(buffer[strlen(SONG_MTIME)]));
|
song->mtime = atoi(&(buffer[strlen(SONG_MTIME)]));
|
||||||
}
|
}
|
||||||
/* ignore empty lines (starting with '\0') */
|
/* ignore empty lines (starting with '\0') */
|
||||||
else if(*buffer){
|
else if (*buffer) {
|
||||||
ERROR("songinfo: unknown line in db: %s\n",buffer);
|
ERROR("songinfo: unknown line in db: %s\n", buffer);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(song) {
|
if (song) {
|
||||||
insertSongIntoList(list, &nextSongNode, song->url, song);
|
insertSongIntoList(list, &nextSongNode, song->url, song);
|
||||||
song = NULL;
|
song = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(nextSongNode) {
|
while (nextSongNode) {
|
||||||
nodeTemp = nextSongNode->nextNode;
|
nodeTemp = nextSongNode->nextNode;
|
||||||
deleteNodeFromList(list,nextSongNode);
|
deleteNodeFromList(list, nextSongNode);
|
||||||
nextSongNode = nodeTemp;
|
nextSongNode = nodeTemp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int updateSongInfo(Song * song) {
|
int updateSongInfo(Song * song)
|
||||||
if(song->type == SONG_TYPE_FILE) {
|
{
|
||||||
InputPlugin * plugin;
|
if (song->type == SONG_TYPE_FILE) {
|
||||||
|
InputPlugin *plugin;
|
||||||
unsigned int next = 0;
|
unsigned int next = 0;
|
||||||
char * song_url = getSongUrl(song);
|
char *song_url = getSongUrl(song);
|
||||||
char * abs_path = rmp2amp(song_url);
|
char *abs_path = rmp2amp(song_url);
|
||||||
|
|
||||||
if(song->tag) freeMpdTag(song->tag);
|
if (song->tag)
|
||||||
|
freeMpdTag(song->tag);
|
||||||
|
|
||||||
song->tag = NULL;
|
song->tag = NULL;
|
||||||
|
|
||||||
while(!song->tag && (plugin = isMusic(song_url,
|
while (!song->tag && (plugin = isMusic(song_url,
|
||||||
&(song->mtime), next++))) {
|
&(song->mtime),
|
||||||
|
next++))) {
|
||||||
song->tag = plugin->tagDupFunc(abs_path);
|
song->tag = plugin->tagDupFunc(abs_path);
|
||||||
}
|
}
|
||||||
if(!song->tag || song->tag->time<0) return -1;
|
if (!song->tag || song->tag->time < 0)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -302,37 +318,40 @@ int updateSongInfo(Song * song) {
|
|||||||
|
|
||||||
/* pass song = NULL to reset, we do this freeJustSong(), so that if
|
/* pass song = NULL to reset, we do this freeJustSong(), so that if
|
||||||
* we free and recreate this memory we make sure to print it correctly*/
|
* we free and recreate this memory we make sure to print it correctly*/
|
||||||
char * getSongUrl(Song * song) {
|
char *getSongUrl(Song * song)
|
||||||
static char * buffer = NULL;
|
{
|
||||||
|
static char *buffer = NULL;
|
||||||
static int bufferSize = 0;
|
static int bufferSize = 0;
|
||||||
static Song * lastSong = NULL;
|
static Song *lastSong = NULL;
|
||||||
int slen;
|
int slen;
|
||||||
int dlen;
|
int dlen;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
if(!song) {
|
if (!song) {
|
||||||
lastSong = song;
|
lastSong = song;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!song->parentDir || !song->parentDir->path) return song->url;
|
if (!song->parentDir || !song->parentDir->path)
|
||||||
|
return song->url;
|
||||||
|
|
||||||
/* be careful with this!*/
|
/* be careful with this! */
|
||||||
if(song == lastSong) return buffer;
|
if (song == lastSong)
|
||||||
|
return buffer;
|
||||||
|
|
||||||
slen = strlen(song->url);
|
slen = strlen(song->url);
|
||||||
dlen = strlen(getDirectoryPath(song->parentDir));
|
dlen = strlen(getDirectoryPath(song->parentDir));
|
||||||
|
|
||||||
size = slen+dlen+2;
|
size = slen + dlen + 2;
|
||||||
|
|
||||||
if(size > bufferSize) {
|
if (size > bufferSize) {
|
||||||
buffer = realloc(buffer, size);
|
buffer = realloc(buffer, size);
|
||||||
bufferSize = size;
|
bufferSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(buffer, getDirectoryPath(song->parentDir));
|
strcpy(buffer, getDirectoryPath(song->parentDir));
|
||||||
buffer[dlen] = '/';
|
buffer[dlen] = '/';
|
||||||
strcpy(buffer+dlen+1, song->url);
|
strcpy(buffer + dlen + 1, song->url);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
20
src/song.h
20
src/song.h
@ -34,29 +34,29 @@
|
|||||||
#define SONG_TYPE_URL 2
|
#define SONG_TYPE_URL 2
|
||||||
|
|
||||||
typedef struct _Song {
|
typedef struct _Song {
|
||||||
char * url;
|
char *url;
|
||||||
mpd_sint8 type;
|
mpd_sint8 type;
|
||||||
MpdTag * tag;
|
MpdTag *tag;
|
||||||
struct _Directory * parentDir;
|
struct _Directory *parentDir;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
} Song;
|
} Song;
|
||||||
|
|
||||||
typedef List SongList;
|
typedef List SongList;
|
||||||
|
|
||||||
Song * newNullSong();
|
Song *newNullSong();
|
||||||
|
|
||||||
Song * newSong(char * url, int songType, struct _Directory * parentDir);
|
Song *newSong(char *url, int songType, struct _Directory *parentDir);
|
||||||
|
|
||||||
void freeSong(Song *);
|
void freeSong(Song *);
|
||||||
|
|
||||||
void freeJustSong(Song *);
|
void freeJustSong(Song *);
|
||||||
|
|
||||||
SongList * newSongList();
|
SongList *newSongList();
|
||||||
|
|
||||||
void freeSongList(SongList * list);
|
void freeSongList(SongList * list);
|
||||||
|
|
||||||
Song * addSongToList(SongList * list, char * url, char * utf8path,
|
Song *addSongToList(SongList * list, char *url, char *utf8path,
|
||||||
int songType, struct _Directory * parentDir);
|
int songType, struct _Directory *parentDir);
|
||||||
|
|
||||||
int printSongInfo(FILE * fp, Song * song);
|
int printSongInfo(FILE * fp, Song * song);
|
||||||
|
|
||||||
@ -65,12 +65,12 @@ int printSongInfoFromList(FILE * fp, SongList * list);
|
|||||||
void writeSongInfoFromList(FILE * fp, SongList * list);
|
void writeSongInfoFromList(FILE * fp, SongList * list);
|
||||||
|
|
||||||
void readSongInfoIntoList(FILE * fp, SongList * list,
|
void readSongInfoIntoList(FILE * fp, SongList * list,
|
||||||
struct _Directory * parent);
|
struct _Directory *parent);
|
||||||
|
|
||||||
int updateSongInfo(Song * song);
|
int updateSongInfo(Song * song);
|
||||||
|
|
||||||
void printSongUrl(FILE * fp, Song * song);
|
void printSongUrl(FILE * fp, Song * song);
|
||||||
|
|
||||||
char * getSongUrl(Song * song);
|
char *getSongUrl(Song * song);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
21
src/stats.c
21
src/stats.c
@ -28,18 +28,21 @@
|
|||||||
|
|
||||||
Stats stats;
|
Stats stats;
|
||||||
|
|
||||||
void initStats(void) {
|
void initStats(void)
|
||||||
|
{
|
||||||
stats.daemonStart = time(NULL);
|
stats.daemonStart = time(NULL);
|
||||||
stats.numberOfSongs = 0;
|
stats.numberOfSongs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int printStats(FILE * fp) {
|
int printStats(FILE * fp)
|
||||||
myfprintf(fp,"artists: %li\n", getNumberOfTagItems(TAG_ITEM_ARTIST));
|
{
|
||||||
myfprintf(fp,"albums: %li\n", getNumberOfTagItems(TAG_ITEM_ALBUM));
|
myfprintf(fp, "artists: %li\n", getNumberOfTagItems(TAG_ITEM_ARTIST));
|
||||||
myfprintf(fp,"songs: %i\n",stats.numberOfSongs);
|
myfprintf(fp, "albums: %li\n", getNumberOfTagItems(TAG_ITEM_ALBUM));
|
||||||
myfprintf(fp,"uptime: %li\n",time(NULL)-stats.daemonStart);
|
myfprintf(fp, "songs: %i\n", stats.numberOfSongs);
|
||||||
myfprintf(fp,"playtime: %li\n",(long)(getPlayerTotalPlayTime()+0.5));
|
myfprintf(fp, "uptime: %li\n", time(NULL) - stats.daemonStart);
|
||||||
myfprintf(fp,"db_playtime: %li\n",stats.dbPlayTime);
|
myfprintf(fp, "playtime: %li\n",
|
||||||
myfprintf(fp,"db_update: %li\n",getDbModTime());
|
(long)(getPlayerTotalPlayTime() + 0.5));
|
||||||
|
myfprintf(fp, "db_playtime: %li\n", stats.dbPlayTime);
|
||||||
|
myfprintf(fp, "db_update: %li\n", getDbModTime());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ typedef struct _Stats {
|
|||||||
int numberOfSongs;
|
int numberOfSongs;
|
||||||
unsigned long dbPlayTime;
|
unsigned long dbPlayTime;
|
||||||
/*unsigned long playTime;
|
/*unsigned long playTime;
|
||||||
unsigned long songsPlayed;*/
|
unsigned long songsPlayed; */
|
||||||
} Stats;
|
} Stats;
|
||||||
|
|
||||||
extern Stats stats;
|
extern Stats stats;
|
||||||
|
316
src/tag.c
316
src/tag.c
@ -55,8 +55,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char * mpdTagItemKeys[TAG_NUM_OF_ITEM_TYPES] =
|
char *mpdTagItemKeys[TAG_NUM_OF_ITEM_TYPES] = {
|
||||||
{
|
|
||||||
"Artist",
|
"Artist",
|
||||||
"Album",
|
"Album",
|
||||||
"Title",
|
"Title",
|
||||||
@ -72,12 +71,13 @@ char * mpdTagItemKeys[TAG_NUM_OF_ITEM_TYPES] =
|
|||||||
|
|
||||||
static mpd_sint8 ignoreTagItems[TAG_NUM_OF_ITEM_TYPES];
|
static mpd_sint8 ignoreTagItems[TAG_NUM_OF_ITEM_TYPES];
|
||||||
|
|
||||||
void initTagConfig(void) {
|
void initTagConfig(void)
|
||||||
|
{
|
||||||
int quit = 0;
|
int quit = 0;
|
||||||
char * temp;
|
char *temp;
|
||||||
char * s;
|
char *s;
|
||||||
char * c;
|
char *c;
|
||||||
ConfigParam * param;
|
ConfigParam *param;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* parse the "metadata_to_use" config parameter below */
|
/* parse the "metadata_to_use" config parameter below */
|
||||||
@ -87,24 +87,27 @@ void initTagConfig(void) {
|
|||||||
|
|
||||||
param = getConfigParam(CONF_METADATA_TO_USE);
|
param = getConfigParam(CONF_METADATA_TO_USE);
|
||||||
|
|
||||||
if(!param) return;
|
if (!param)
|
||||||
|
return;
|
||||||
|
|
||||||
memset(ignoreTagItems, 1, TAG_NUM_OF_ITEM_TYPES);
|
memset(ignoreTagItems, 1, TAG_NUM_OF_ITEM_TYPES);
|
||||||
|
|
||||||
if(0 == strcasecmp(param->value, "none")) return;
|
if (0 == strcasecmp(param->value, "none"))
|
||||||
|
return;
|
||||||
|
|
||||||
temp = c = s = strdup(param->value);
|
temp = c = s = strdup(param->value);
|
||||||
while(!quit) {
|
while (!quit) {
|
||||||
if(*s == ',' || *s == '\0') {
|
if (*s == ',' || *s == '\0') {
|
||||||
if(*s == '\0') quit = 1;
|
if (*s == '\0')
|
||||||
|
quit = 1;
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
||||||
if(strcasecmp(c, mpdTagItemKeys[i]) == 0) {
|
if (strcasecmp(c, mpdTagItemKeys[i]) == 0) {
|
||||||
ignoreTagItems[i] = 0;
|
ignoreTagItems[i] = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(strlen(c) && i == TAG_NUM_OF_ITEM_TYPES) {
|
if (strlen(c) && i == TAG_NUM_OF_ITEM_TYPES) {
|
||||||
ERROR("error parsing metadata item \"%s\" at "
|
ERROR("error parsing metadata item \"%s\" at "
|
||||||
"line %i\n", c, param->line);
|
"line %i\n", c, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -118,47 +121,53 @@ void initTagConfig(void) {
|
|||||||
free(temp);
|
free(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printMpdTag(FILE * fp, MpdTag * tag) {
|
void printMpdTag(FILE * fp, MpdTag * tag)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(tag->time>=0) myfprintf(fp,"Time: %i\n",tag->time);
|
if (tag->time >= 0)
|
||||||
|
myfprintf(fp, "Time: %i\n", tag->time);
|
||||||
|
|
||||||
for(i = 0; i < tag->numOfItems; i++) {
|
for (i = 0; i < tag->numOfItems; i++) {
|
||||||
myfprintf(fp, "%s: %s\n", mpdTagItemKeys[tag->items[i].type],
|
myfprintf(fp, "%s: %s\n", mpdTagItemKeys[tag->items[i].type],
|
||||||
tag->items[i].value);
|
tag->items[i].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
MpdTag * getID3Info(struct id3_tag * tag, char * id, int type, MpdTag * mpdTag)
|
MpdTag *getID3Info(struct id3_tag *tag, char *id, int type, MpdTag * mpdTag)
|
||||||
{
|
{
|
||||||
struct id3_frame const * frame;
|
struct id3_frame const *frame;
|
||||||
id3_ucs4_t const * ucs4;
|
id3_ucs4_t const *ucs4;
|
||||||
id3_utf8_t * utf8;
|
id3_utf8_t *utf8;
|
||||||
union id3_field const * field;
|
union id3_field const *field;
|
||||||
unsigned int nstrings;
|
unsigned int nstrings;
|
||||||
int i;
|
int i;
|
||||||
char * isostr;
|
char *isostr;
|
||||||
char * encoding;
|
char *encoding;
|
||||||
|
|
||||||
frame = id3_tag_findframe(tag, id, 0);
|
frame = id3_tag_findframe(tag, id, 0);
|
||||||
if(!frame || frame->nfields < 2) return mpdTag;
|
if (!frame || frame->nfields < 2)
|
||||||
|
return mpdTag;
|
||||||
|
|
||||||
field = &frame->fields[1];
|
field = &frame->fields[1];
|
||||||
nstrings = id3_field_getnstrings(field);
|
nstrings = id3_field_getnstrings(field);
|
||||||
|
|
||||||
for(i = 0; i < nstrings; i++) {
|
for (i = 0; i < nstrings; i++) {
|
||||||
ucs4 = id3_field_getstrings(field, i);
|
ucs4 = id3_field_getstrings(field, i);
|
||||||
if(!ucs4) continue;
|
if (!ucs4)
|
||||||
|
continue;
|
||||||
|
|
||||||
if(type == TAG_ITEM_GENRE) ucs4 = id3_genre_name(ucs4);
|
if (type == TAG_ITEM_GENRE)
|
||||||
|
ucs4 = id3_genre_name(ucs4);
|
||||||
|
|
||||||
utf8 = id3_ucs4_utf8duplicate(ucs4);
|
utf8 = id3_ucs4_utf8duplicate(ucs4);
|
||||||
if(!utf8) continue;
|
if (!utf8)
|
||||||
|
continue;
|
||||||
|
|
||||||
if(isId3v1(tag)) {
|
if (isId3v1(tag)) {
|
||||||
encoding = getConfigParamValue(CONF_ID3V1_ENCODING);
|
encoding = getConfigParamValue(CONF_ID3V1_ENCODING);
|
||||||
if(encoding) {
|
if (encoding) {
|
||||||
setCharSetConversion("ISO-8859-1", "UTF-8");
|
setCharSetConversion("ISO-8859-1", "UTF-8");
|
||||||
isostr = convStrDup(utf8);
|
isostr = convStrDup(utf8);
|
||||||
free(utf8);
|
free(utf8);
|
||||||
@ -168,7 +177,8 @@ MpdTag * getID3Info(struct id3_tag * tag, char * id, int type, MpdTag * mpdTag)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mpdTag == NULL) mpdTag = newMpdTag();
|
if (mpdTag == NULL)
|
||||||
|
mpdTag = newMpdTag();
|
||||||
addItemToMpdTag(mpdTag, type, utf8);
|
addItemToMpdTag(mpdTag, type, utf8);
|
||||||
|
|
||||||
free(utf8);
|
free(utf8);
|
||||||
@ -179,8 +189,9 @@ MpdTag * getID3Info(struct id3_tag * tag, char * id, int type, MpdTag * mpdTag)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
MpdTag * parseId3Tag(struct id3_tag * tag) {
|
MpdTag *parseId3Tag(struct id3_tag * tag)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
|
MpdTag *ret = NULL;
|
||||||
|
|
||||||
ret = getID3Info(tag, ID3_FRAME_ARTIST, TAG_ITEM_ARTIST, ret);
|
ret = getID3Info(tag, ID3_FRAME_ARTIST, TAG_ITEM_ARTIST, ret);
|
||||||
ret = getID3Info(tag, ID3_FRAME_TITLE, TAG_ITEM_TITLE, ret);
|
ret = getID3Info(tag, ID3_FRAME_TITLE, TAG_ITEM_TITLE, ret);
|
||||||
@ -197,10 +208,11 @@ MpdTag * parseId3Tag(struct id3_tag * tag) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
static int fillBuffer(void *buf, size_t size, FILE *stream,
|
static int fillBuffer(void *buf, size_t size, FILE * stream,
|
||||||
long offset, int whence)
|
long offset, int whence)
|
||||||
{
|
{
|
||||||
if (fseek(stream, offset, whence) != 0) return 0;
|
if (fseek(stream, offset, whence) != 0)
|
||||||
|
return 0;
|
||||||
return fread(buf, 1, size, stream);
|
return fread(buf, 1, size, stream);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -212,28 +224,31 @@ static int getId3v2FooterSize(FILE * stream, long offset, int whence)
|
|||||||
int bufsize;
|
int bufsize;
|
||||||
|
|
||||||
bufsize = fillBuffer(buf, ID3_TAG_QUERYSIZE, stream, offset, whence);
|
bufsize = fillBuffer(buf, ID3_TAG_QUERYSIZE, stream, offset, whence);
|
||||||
if (bufsize <= 0) return 0;
|
if (bufsize <= 0)
|
||||||
|
return 0;
|
||||||
return id3_tag_query(buf, bufsize);
|
return id3_tag_query(buf, bufsize);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
static struct id3_tag * getId3Tag(FILE * stream, long offset, int whence)
|
static struct id3_tag *getId3Tag(FILE * stream, long offset, int whence)
|
||||||
{
|
{
|
||||||
struct id3_tag * tag;
|
struct id3_tag *tag;
|
||||||
id3_byte_t * buf[ID3_TAG_BUFLEN];
|
id3_byte_t *buf[ID3_TAG_BUFLEN];
|
||||||
id3_byte_t * mbuf;
|
id3_byte_t *mbuf;
|
||||||
int tagsize;
|
int tagsize;
|
||||||
int bufsize;
|
int bufsize;
|
||||||
int mbufsize;
|
int mbufsize;
|
||||||
|
|
||||||
/* It's ok if we get less than we asked for */
|
/* It's ok if we get less than we asked for */
|
||||||
bufsize = fillBuffer(buf, ID3_TAG_BUFLEN, stream, offset, whence);
|
bufsize = fillBuffer(buf, ID3_TAG_BUFLEN, stream, offset, whence);
|
||||||
if (bufsize <= 0) return NULL;
|
if (bufsize <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* Look for a tag header */
|
/* Look for a tag header */
|
||||||
tagsize = id3_tag_query((const id3_byte_t *)buf, bufsize);
|
tagsize = id3_tag_query((const id3_byte_t *)buf, bufsize);
|
||||||
if (tagsize <= 0) return NULL;
|
if (tagsize <= 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (tagsize <= bufsize) {
|
if (tagsize <= bufsize) {
|
||||||
/* Got an id3 tag, and it fits in buf */
|
/* Got an id3 tag, and it fits in buf */
|
||||||
@ -241,7 +256,8 @@ static struct id3_tag * getId3Tag(FILE * stream, long offset, int whence)
|
|||||||
} else {
|
} else {
|
||||||
/* Got an id3tag that overflows buf, so get a new one */
|
/* Got an id3tag that overflows buf, so get a new one */
|
||||||
mbuf = malloc(tagsize);
|
mbuf = malloc(tagsize);
|
||||||
if (!mbuf) return NULL;
|
if (!mbuf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
mbufsize = fillBuffer(mbuf, tagsize, stream, offset, whence);
|
mbufsize = fillBuffer(mbuf, tagsize, stream, offset, whence);
|
||||||
if (mbufsize < tagsize) {
|
if (mbufsize < tagsize) {
|
||||||
@ -259,11 +275,11 @@ static struct id3_tag * getId3Tag(FILE * stream, long offset, int whence)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
static struct id3_tag * findId3TagFromBeginning(FILE * stream)
|
static struct id3_tag *findId3TagFromBeginning(FILE * stream)
|
||||||
{
|
{
|
||||||
struct id3_tag * tag;
|
struct id3_tag *tag;
|
||||||
struct id3_tag * seektag;
|
struct id3_tag *seektag;
|
||||||
struct id3_frame * frame;
|
struct id3_frame *frame;
|
||||||
int seek;
|
int seek;
|
||||||
|
|
||||||
tag = getId3Tag(stream, 0, SEEK_SET);
|
tag = getId3Tag(stream, 0, SEEK_SET);
|
||||||
@ -279,11 +295,13 @@ static struct id3_tag * findId3TagFromBeginning(FILE * stream)
|
|||||||
while ((frame = id3_tag_findframe(tag, "SEEK", 0))) {
|
while ((frame = id3_tag_findframe(tag, "SEEK", 0))) {
|
||||||
/* Found a SEEK frame, get it's value */
|
/* Found a SEEK frame, get it's value */
|
||||||
seek = id3_field_getint(id3_frame_field(frame, 0));
|
seek = id3_field_getint(id3_frame_field(frame, 0));
|
||||||
if (seek < 0) break;
|
if (seek < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
/* Get the tag specified by the SEEK frame */
|
/* Get the tag specified by the SEEK frame */
|
||||||
seektag = getId3Tag(stream, seek, SEEK_CUR);
|
seektag = getId3Tag(stream, seek, SEEK_CUR);
|
||||||
if (!seektag || isId3v1(seektag)) break;
|
if (!seektag || isId3v1(seektag))
|
||||||
|
break;
|
||||||
|
|
||||||
/* Replace the old tag with the new one */
|
/* Replace the old tag with the new one */
|
||||||
id3_tag_delete(tag);
|
id3_tag_delete(tag);
|
||||||
@ -295,10 +313,10 @@ static struct id3_tag * findId3TagFromBeginning(FILE * stream)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
static struct id3_tag * findId3TagFromEnd(FILE * stream)
|
static struct id3_tag *findId3TagFromEnd(FILE * stream)
|
||||||
{
|
{
|
||||||
struct id3_tag * tag;
|
struct id3_tag *tag;
|
||||||
struct id3_tag * v1tag;
|
struct id3_tag *v1tag;
|
||||||
int tagsize;
|
int tagsize;
|
||||||
|
|
||||||
/* Get an id3v1 tag from the end of file for later use */
|
/* Get an id3v1 tag from the end of file for later use */
|
||||||
@ -306,11 +324,13 @@ static struct id3_tag * findId3TagFromEnd(FILE * stream)
|
|||||||
|
|
||||||
/* Get the id3v2 tag size from the footer (located before v1tag) */
|
/* Get the id3v2 tag size from the footer (located before v1tag) */
|
||||||
tagsize = getId3v2FooterSize(stream, (v1tag ? -128 : 0) - 10, SEEK_END);
|
tagsize = getId3v2FooterSize(stream, (v1tag ? -128 : 0) - 10, SEEK_END);
|
||||||
if (tagsize >= 0) return v1tag;
|
if (tagsize >= 0)
|
||||||
|
return v1tag;
|
||||||
|
|
||||||
/* Get the tag which the footer belongs to */
|
/* Get the tag which the footer belongs to */
|
||||||
tag = getId3Tag(stream, tagsize, SEEK_CUR);
|
tag = getId3Tag(stream, tagsize, SEEK_CUR);
|
||||||
if (!tag) return v1tag;
|
if (!tag)
|
||||||
|
return v1tag;
|
||||||
|
|
||||||
/* We have an id3v2 tag, so ditch v1tag */
|
/* We have an id3v2 tag, so ditch v1tag */
|
||||||
id3_tag_delete(v1tag);
|
id3_tag_delete(v1tag);
|
||||||
@ -319,41 +339,46 @@ static struct id3_tag * findId3TagFromEnd(FILE * stream)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MpdTag * id3Dup(char * file) {
|
MpdTag *id3Dup(char *file)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
|
MpdTag *ret = NULL;
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
struct id3_tag * tag;
|
struct id3_tag *tag;
|
||||||
FILE * stream;
|
FILE *stream;
|
||||||
|
|
||||||
stream = fopen(file, "r");
|
stream = fopen(file, "r");
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
DEBUG("id3Dup: Failed to open file: '%s', %s\n",file, strerror(errno));
|
DEBUG("id3Dup: Failed to open file: '%s', %s\n", file,
|
||||||
|
strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
tag = findId3TagFromBeginning(stream);
|
tag = findId3TagFromBeginning(stream);
|
||||||
if (!tag) tag = findId3TagFromEnd(stream);
|
if (!tag)
|
||||||
|
tag = findId3TagFromEnd(stream);
|
||||||
|
|
||||||
fclose(stream);
|
fclose(stream);
|
||||||
|
|
||||||
if (!tag) return NULL;
|
if (!tag)
|
||||||
|
return NULL;
|
||||||
ret = parseId3Tag(tag);
|
ret = parseId3Tag(tag);
|
||||||
id3_tag_delete(tag);
|
id3_tag_delete(tag);
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MpdTag * apeDup(char * file) {
|
MpdTag *apeDup(char *file)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
FILE * fp = NULL;
|
MpdTag *ret = NULL;
|
||||||
|
FILE *fp = NULL;
|
||||||
int tagCount;
|
int tagCount;
|
||||||
char * buffer = NULL;
|
char *buffer = NULL;
|
||||||
char * p;
|
char *p;
|
||||||
int tagLen;
|
int tagLen;
|
||||||
int size;
|
int size;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i;
|
int i;
|
||||||
char * key;
|
char *key;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned char id[8];
|
unsigned char id[8];
|
||||||
@ -364,8 +389,7 @@ MpdTag * apeDup(char * file) {
|
|||||||
unsigned char reserved[8];
|
unsigned char reserved[8];
|
||||||
} footer;
|
} footer;
|
||||||
|
|
||||||
char * apeItems[7] =
|
char *apeItems[7] = {
|
||||||
{
|
|
||||||
"title",
|
"title",
|
||||||
"artist",
|
"artist",
|
||||||
"album",
|
"album",
|
||||||
@ -375,8 +399,7 @@ MpdTag * apeDup(char * file) {
|
|||||||
"year"
|
"year"
|
||||||
};
|
};
|
||||||
|
|
||||||
int tagItems[7] =
|
int tagItems[7] = {
|
||||||
{
|
|
||||||
TAG_ITEM_TITLE,
|
TAG_ITEM_TITLE,
|
||||||
TAG_ITEM_ARTIST,
|
TAG_ITEM_ARTIST,
|
||||||
TAG_ITEM_ALBUM,
|
TAG_ITEM_ALBUM,
|
||||||
@ -387,30 +410,39 @@ MpdTag * apeDup(char * file) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fp = fopen(file, "r");
|
fp = fopen(file, "r");
|
||||||
if(!fp) return NULL;
|
if (!fp)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* determine if file has an apeV2 tag */
|
/* determine if file has an apeV2 tag */
|
||||||
if(fseek(fp, 0, SEEK_END)) goto fail;
|
if (fseek(fp, 0, SEEK_END))
|
||||||
|
goto fail;
|
||||||
size = ftell(fp);
|
size = ftell(fp);
|
||||||
if(fseek(fp, size-sizeof(footer), SEEK_SET)) goto fail;
|
if (fseek(fp, size - sizeof(footer), SEEK_SET))
|
||||||
if(fread(&footer, 1, sizeof(footer), fp) != sizeof(footer)) goto fail;
|
goto fail;
|
||||||
if(memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0) goto fail;
|
if (fread(&footer, 1, sizeof(footer), fp) != sizeof(footer))
|
||||||
if(readLEuint32(footer.version) != 2000) goto fail;
|
goto fail;
|
||||||
|
if (memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0)
|
||||||
|
goto fail;
|
||||||
|
if (readLEuint32(footer.version) != 2000)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* find begining of ape tag */
|
/* find begining of ape tag */
|
||||||
tagLen = readLEuint32(footer.length);
|
tagLen = readLEuint32(footer.length);
|
||||||
if(tagLen < sizeof(footer)) goto fail;
|
if (tagLen < sizeof(footer))
|
||||||
if(fseek(fp, size-tagLen, SEEK_SET)) goto fail;
|
goto fail;
|
||||||
|
if (fseek(fp, size - tagLen, SEEK_SET))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* read tag into buffer */
|
/* read tag into buffer */
|
||||||
tagLen -= sizeof(footer);
|
tagLen -= sizeof(footer);
|
||||||
buffer = malloc(tagLen);
|
buffer = malloc(tagLen);
|
||||||
if(fread(buffer, 1, tagLen, fp) != tagLen) goto fail;
|
if (fread(buffer, 1, tagLen, fp) != tagLen)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* read tags */
|
/* read tags */
|
||||||
tagCount = readLEuint32(footer.tagCount);
|
tagCount = readLEuint32(footer.tagCount);
|
||||||
p = buffer;
|
p = buffer;
|
||||||
while(tagCount-- && tagLen > 10) {
|
while (tagCount-- && tagLen > 10) {
|
||||||
size = readLEuint32((unsigned char *)p);
|
size = readLEuint32((unsigned char *)p);
|
||||||
p += 4;
|
p += 4;
|
||||||
tagLen -= 4;
|
tagLen -= 4;
|
||||||
@ -420,7 +452,7 @@ MpdTag * apeDup(char * file) {
|
|||||||
|
|
||||||
/* get the key */
|
/* get the key */
|
||||||
key = p;
|
key = p;
|
||||||
while(tagLen-size > 0 && *p != '\0') {
|
while (tagLen - size > 0 && *p != '\0') {
|
||||||
p++;
|
p++;
|
||||||
tagLen--;
|
tagLen--;
|
||||||
}
|
}
|
||||||
@ -428,15 +460,17 @@ MpdTag * apeDup(char * file) {
|
|||||||
tagLen--;
|
tagLen--;
|
||||||
|
|
||||||
/* get the value */
|
/* get the value */
|
||||||
if(tagLen-size < 0) goto fail;
|
if (tagLen - size < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* we only care about utf-8 text tags */
|
/* we only care about utf-8 text tags */
|
||||||
if(!(flags & (0x3 << 1))) {
|
if (!(flags & (0x3 << 1))) {
|
||||||
for(i = 0; i < 7; i++) {
|
for (i = 0; i < 7; i++) {
|
||||||
if(strcasecmp(key, apeItems[i]) == 0) {
|
if (strcasecmp(key, apeItems[i]) == 0) {
|
||||||
if(!ret) ret = newMpdTag();
|
if (!ret)
|
||||||
addItemToMpdTagWithLen(
|
ret = newMpdTag();
|
||||||
ret, tagItems[i], p, size);
|
addItemToMpdTagWithLen(ret, tagItems[i],
|
||||||
|
p, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -444,21 +478,25 @@ MpdTag * apeDup(char * file) {
|
|||||||
tagLen -= size;
|
tagLen -= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
if(fp) fclose(fp);
|
if (fp)
|
||||||
if(buffer) free(buffer);
|
fclose(fp);
|
||||||
|
if (buffer)
|
||||||
|
free(buffer);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
MpdTag * newMpdTag(void) {
|
MpdTag *newMpdTag(void)
|
||||||
MpdTag * ret = malloc(sizeof(MpdTag));
|
{
|
||||||
|
MpdTag *ret = malloc(sizeof(MpdTag));
|
||||||
ret->items = NULL;
|
ret->items = NULL;
|
||||||
ret->time = -1;
|
ret->time = -1;
|
||||||
ret->numOfItems = 0;
|
ret->numOfItems = 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deleteItem(MpdTag * tag, int index) {
|
static void deleteItem(MpdTag * tag, int index)
|
||||||
|
{
|
||||||
tag->numOfItems--;
|
tag->numOfItems--;
|
||||||
|
|
||||||
assert(index < tag->numOfItems);
|
assert(index < tag->numOfItems);
|
||||||
@ -466,26 +504,26 @@ static void deleteItem(MpdTag * tag, int index) {
|
|||||||
removeTagItemString(tag->items[index].type, tag->items[index].value);
|
removeTagItemString(tag->items[index].type, tag->items[index].value);
|
||||||
/* free(tag->items[index].value); */
|
/* free(tag->items[index].value); */
|
||||||
|
|
||||||
if(tag->numOfItems-index > 0) {
|
if (tag->numOfItems - index > 0) {
|
||||||
memmove(tag->items+index, tag->items+index+1,
|
memmove(tag->items + index, tag->items + index + 1,
|
||||||
tag->numOfItems-index);
|
tag->numOfItems - index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tag->numOfItems > 0) {
|
if (tag->numOfItems > 0) {
|
||||||
tag->items = realloc(tag->items,
|
tag->items = realloc(tag->items,
|
||||||
tag->numOfItems*sizeof(MpdTagItem));
|
tag->numOfItems * sizeof(MpdTagItem));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
free(tag->items);
|
free(tag->items);
|
||||||
tag->items = NULL;
|
tag->items = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearItemsFromMpdTag(MpdTag * tag, int type) {
|
void clearItemsFromMpdTag(MpdTag * tag, int type)
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for(i = 0; i < tag->numOfItems; i++) {
|
for (i = 0; i < tag->numOfItems; i++) {
|
||||||
if(tag->items[i].type == type) {
|
if (tag->items[i].type == type) {
|
||||||
deleteItem(tag, i);
|
deleteItem(tag, i);
|
||||||
/* decrement since when just deleted this node */
|
/* decrement since when just deleted this node */
|
||||||
i--;
|
i--;
|
||||||
@ -493,15 +531,17 @@ void clearItemsFromMpdTag(MpdTag * tag, int type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clearMpdTag(MpdTag * tag) {
|
static void clearMpdTag(MpdTag * tag)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < tag->numOfItems; i++) {
|
for (i = 0; i < tag->numOfItems; i++) {
|
||||||
removeTagItemString(tag->items[i].type, tag->items[i].value);
|
removeTagItemString(tag->items[i].type, tag->items[i].value);
|
||||||
/* free(tag->items[i].value); */
|
/* free(tag->items[i].value); */
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tag->items) free(tag->items);
|
if (tag->items)
|
||||||
|
free(tag->items);
|
||||||
tag->items = NULL;
|
tag->items = NULL;
|
||||||
|
|
||||||
tag->numOfItems = 0;
|
tag->numOfItems = 0;
|
||||||
@ -509,40 +549,49 @@ static void clearMpdTag(MpdTag * tag) {
|
|||||||
tag->time = -1;
|
tag->time = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeMpdTag(MpdTag * tag) {
|
void freeMpdTag(MpdTag * tag)
|
||||||
|
{
|
||||||
clearMpdTag(tag);
|
clearMpdTag(tag);
|
||||||
free(tag);
|
free(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
MpdTag * mpdTagDup(MpdTag * tag) {
|
MpdTag *mpdTagDup(MpdTag * tag)
|
||||||
MpdTag * ret = NULL;
|
{
|
||||||
|
MpdTag *ret = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(!tag) return NULL;
|
if (!tag)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
ret = newMpdTag();
|
ret = newMpdTag();
|
||||||
ret->time = tag->time;
|
ret->time = tag->time;
|
||||||
|
|
||||||
for(i = 0; i < tag->numOfItems; i++) {
|
for (i = 0; i < tag->numOfItems; i++) {
|
||||||
addItemToMpdTag(ret, tag->items[i].type, tag->items[i].value);
|
addItemToMpdTag(ret, tag->items[i].type, tag->items[i].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2) {
|
int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if(tag1 == NULL && tag2 == NULL) return 1;
|
if (tag1 == NULL && tag2 == NULL)
|
||||||
else if(!tag1 || !tag2) return 0;
|
return 1;
|
||||||
|
else if (!tag1 || !tag2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if(tag1->time != tag2->time) return 0;
|
if (tag1->time != tag2->time)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if(tag1->numOfItems != tag2->numOfItems) return 0;
|
if (tag1->numOfItems != tag2->numOfItems)
|
||||||
|
return 0;
|
||||||
|
|
||||||
for(i = 0; i < tag1->numOfItems; i++) {
|
for (i = 0; i < tag1->numOfItems; i++) {
|
||||||
if(tag1->items[i].type != tag2->items[i].type) return 0;
|
if (tag1->items[i].type != tag2->items[i].type)
|
||||||
if(strcmp(tag1->items[i].value, tag2->items[i].value)) {
|
return 0;
|
||||||
|
if (strcmp(tag1->items[i].value, tag2->items[i].value)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -560,13 +609,12 @@ int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2) {
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void appendToTagItems(MpdTag * tag, int type, char * value,
|
static void appendToTagItems(MpdTag * tag, int type, char *value, int len)
|
||||||
int len)
|
|
||||||
{
|
{
|
||||||
int i = tag->numOfItems;
|
int i = tag->numOfItems;
|
||||||
|
|
||||||
char * dup;
|
char *dup;
|
||||||
dup = malloc(len+1);
|
dup = malloc(len + 1);
|
||||||
strncpy(dup, value, len);
|
strncpy(dup, value, len);
|
||||||
dup[len] = '\0';
|
dup[len] = '\0';
|
||||||
|
|
||||||
@ -574,7 +622,7 @@ static void appendToTagItems(MpdTag * tag, int type, char * value,
|
|||||||
stripReturnChar(dup);
|
stripReturnChar(dup);
|
||||||
|
|
||||||
tag->numOfItems++;
|
tag->numOfItems++;
|
||||||
tag->items = realloc(tag->items, tag->numOfItems*sizeof(MpdTagItem));
|
tag->items = realloc(tag->items, tag->numOfItems * sizeof(MpdTagItem));
|
||||||
|
|
||||||
tag->items[i].type = type;
|
tag->items[i].type = type;
|
||||||
tag->items[i].value = getTagItemString(type, dup);
|
tag->items[i].value = getTagItemString(type, dup);
|
||||||
@ -582,13 +630,17 @@ static void appendToTagItems(MpdTag * tag, int type, char * value,
|
|||||||
free(dup);
|
free(dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addItemToMpdTagWithLen(MpdTag * tag, int itemType, char * value, int len) {
|
void addItemToMpdTagWithLen(MpdTag * tag, int itemType, char *value, int len)
|
||||||
if(ignoreTagItems[itemType]) return;
|
{
|
||||||
|
if (ignoreTagItems[itemType])
|
||||||
|
return;
|
||||||
|
|
||||||
if(!value || !len) return;
|
if (!value || !len)
|
||||||
|
return;
|
||||||
|
|
||||||
/* we can't hold more than 255 items */
|
/* we can't hold more than 255 items */
|
||||||
if(tag->numOfItems == 255) return;
|
if (tag->numOfItems == 255)
|
||||||
|
return;
|
||||||
|
|
||||||
appendToTagItems(tag, itemType, value, len);
|
appendToTagItems(tag, itemType, value, len);
|
||||||
}
|
}
|
||||||
|
18
src/tag.h
18
src/tag.h
@ -44,28 +44,28 @@
|
|||||||
|
|
||||||
#define TAG_NUM_OF_ITEM_TYPES 11
|
#define TAG_NUM_OF_ITEM_TYPES 11
|
||||||
|
|
||||||
extern char * mpdTagItemKeys[];
|
extern char *mpdTagItemKeys[];
|
||||||
|
|
||||||
typedef struct _MpdTagItem {
|
typedef struct _MpdTagItem {
|
||||||
mpd_sint8 type;
|
mpd_sint8 type;
|
||||||
char * value;
|
char *value;
|
||||||
} MpdTagItem;
|
} MpdTagItem;
|
||||||
|
|
||||||
typedef struct _MpdTag {
|
typedef struct _MpdTag {
|
||||||
int time;
|
int time;
|
||||||
MpdTagItem * items;
|
MpdTagItem *items;
|
||||||
mpd_uint8 numOfItems;
|
mpd_uint8 numOfItems;
|
||||||
} MpdTag;
|
} MpdTag;
|
||||||
|
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
MpdTag * parseId3Tag(struct id3_tag *);
|
MpdTag *parseId3Tag(struct id3_tag *);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MpdTag * apeDup(char * file);
|
MpdTag *apeDup(char *file);
|
||||||
|
|
||||||
MpdTag * id3Dup(char * file);
|
MpdTag *id3Dup(char *file);
|
||||||
|
|
||||||
MpdTag * newMpdTag();
|
MpdTag *newMpdTag();
|
||||||
|
|
||||||
void initTagConfig();
|
void initTagConfig();
|
||||||
|
|
||||||
@ -73,14 +73,14 @@ void clearItemsFromMpdTag(MpdTag * tag, int itemType);
|
|||||||
|
|
||||||
void freeMpdTag(MpdTag * tag);
|
void freeMpdTag(MpdTag * tag);
|
||||||
|
|
||||||
void addItemToMpdTagWithLen(MpdTag * tag, int itemType, char * value, int len);
|
void addItemToMpdTagWithLen(MpdTag * tag, int itemType, char *value, int len);
|
||||||
|
|
||||||
#define addItemToMpdTag(tag, itemType, value) \
|
#define addItemToMpdTag(tag, itemType, value) \
|
||||||
addItemToMpdTagWithLen(tag, itemType, value, strlen(value))
|
addItemToMpdTagWithLen(tag, itemType, value, strlen(value))
|
||||||
|
|
||||||
void printMpdTag(FILE * fp, MpdTag * tag);
|
void printMpdTag(FILE * fp, MpdTag * tag);
|
||||||
|
|
||||||
MpdTag * mpdTagDup(MpdTag * tag);
|
MpdTag *mpdTagDup(MpdTag * tag);
|
||||||
|
|
||||||
int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2);
|
int mpdTagsAreEqual(MpdTag * tag1, MpdTag * tag2);
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
static List * tagLists[TAG_NUM_OF_ITEM_TYPES] =
|
static List *tagLists[TAG_NUM_OF_ITEM_TYPES] = {
|
||||||
{
|
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -39,20 +38,20 @@ typedef struct tagTrackerItem {
|
|||||||
mpd_sint8 visited;
|
mpd_sint8 visited;
|
||||||
} TagTrackerItem;
|
} TagTrackerItem;
|
||||||
|
|
||||||
char * getTagItemString(int type, char * string) {
|
char *getTagItemString(int type, char *string)
|
||||||
ListNode * node;
|
{
|
||||||
|
ListNode *node;
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
if(tagLists[type] == NULL) {
|
if (tagLists[type] == NULL) {
|
||||||
tagLists[type] = makeList(free, 1);
|
tagLists[type] = makeList(free, 1);
|
||||||
sortList(tagLists[type]);
|
sortList(tagLists[type]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(findNodeInList(tagLists[type], string, &node, &pos)) {
|
if (findNodeInList(tagLists[type], string, &node, &pos)) {
|
||||||
((TagTrackerItem *)node->data)->count++;
|
((TagTrackerItem *) node->data)->count++;
|
||||||
}
|
} else {
|
||||||
else {
|
TagTrackerItem *item = malloc(sizeof(TagTrackerItem));
|
||||||
TagTrackerItem * item = malloc(sizeof(TagTrackerItem));
|
|
||||||
item->count = 1;
|
item->count = 1;
|
||||||
item->visited = 0;
|
item->visited = 0;
|
||||||
node = insertInListBeforeNode(tagLists[type], node, pos,
|
node = insertInListBeforeNode(tagLists[type], node, pos,
|
||||||
@ -62,50 +61,57 @@ char * getTagItemString(int type, char * string) {
|
|||||||
return node->key;
|
return node->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeTagItemString(int type, char * string) {
|
void removeTagItemString(int type, char *string)
|
||||||
ListNode * node;
|
{
|
||||||
|
ListNode *node;
|
||||||
int pos;
|
int pos;
|
||||||
|
|
||||||
assert(string);
|
assert(string);
|
||||||
|
|
||||||
assert(tagLists[type]);
|
assert(tagLists[type]);
|
||||||
if(tagLists[type] == NULL) return;
|
if (tagLists[type] == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
if(findNodeInList(tagLists[type], string, &node, &pos)) {
|
if (findNodeInList(tagLists[type], string, &node, &pos)) {
|
||||||
TagTrackerItem * item = node->data;
|
TagTrackerItem *item = node->data;
|
||||||
item->count--;
|
item->count--;
|
||||||
if(item->count <= 0) deleteNodeFromList(tagLists[type], node);
|
if (item->count <= 0)
|
||||||
|
deleteNodeFromList(tagLists[type], node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tagLists[type]->numberOfNodes == 0) {
|
if (tagLists[type]->numberOfNodes == 0) {
|
||||||
freeList(tagLists[type]);
|
freeList(tagLists[type]);
|
||||||
tagLists[type] = NULL;
|
tagLists[type] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int getNumberOfTagItems(int type) {
|
int getNumberOfTagItems(int type)
|
||||||
if(tagLists[type] == NULL) return 0;
|
{
|
||||||
|
if (tagLists[type] == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return tagLists[type]->numberOfNodes;
|
return tagLists[type]->numberOfNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printMemorySavedByTagTracker(void) {
|
void printMemorySavedByTagTracker(void)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
ListNode * node;
|
ListNode *node;
|
||||||
size_t sum = 0;
|
size_t sum = 0;
|
||||||
|
|
||||||
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
||||||
if(!tagLists[i]) continue;
|
if (!tagLists[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
sum -= sizeof(List);
|
sum -= sizeof(List);
|
||||||
|
|
||||||
node = tagLists[i]->firstNode;
|
node = tagLists[i]->firstNode;
|
||||||
|
|
||||||
while(node != NULL) {
|
while (node != NULL) {
|
||||||
sum -= sizeof(ListNode);
|
sum -= sizeof(ListNode);
|
||||||
sum -= sizeof(TagTrackerItem);
|
sum -= sizeof(TagTrackerItem);
|
||||||
sum -= sizeof(node->key);
|
sum -= sizeof(node->key);
|
||||||
sum += (strlen(node->key)+1)*(*((int *)node->data));
|
sum += (strlen(node->key) + 1) * (*((int *)node->data));
|
||||||
node = node->nextNode;
|
node = node->nextNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,40 +119,47 @@ void printMemorySavedByTagTracker(void) {
|
|||||||
DEBUG("saved memory from tags: %li\n", (long)sum);
|
DEBUG("saved memory from tags: %li\n", (long)sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetVisitedFlagsInTagTracker(int type) {
|
void resetVisitedFlagsInTagTracker(int type)
|
||||||
ListNode * node;
|
{
|
||||||
|
ListNode *node;
|
||||||
|
|
||||||
if(!tagLists[type]) return;
|
if (!tagLists[type])
|
||||||
|
return;
|
||||||
|
|
||||||
node = tagLists[type]->firstNode;
|
node = tagLists[type]->firstNode;
|
||||||
|
|
||||||
while(node) {
|
while (node) {
|
||||||
((TagTrackerItem *)node->data)->visited = 0;
|
((TagTrackerItem *) node->data)->visited = 0;
|
||||||
node = node->nextNode;
|
node = node->nextNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitInTagTracker(int type, char * str) {
|
void visitInTagTracker(int type, char *str)
|
||||||
void * item;
|
{
|
||||||
|
void *item;
|
||||||
|
|
||||||
if(!tagLists[type]) return;
|
if (!tagLists[type])
|
||||||
|
return;
|
||||||
|
|
||||||
if(!findInList(tagLists[type], str, &item)) return;
|
if (!findInList(tagLists[type], str, &item))
|
||||||
|
return;
|
||||||
|
|
||||||
((TagTrackerItem *)item)->visited = 1;
|
((TagTrackerItem *) item)->visited = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printVisitedInTagTracker(FILE * fp, int type) {
|
void printVisitedInTagTracker(FILE * fp, int type)
|
||||||
ListNode * node;
|
{
|
||||||
TagTrackerItem * item;
|
ListNode *node;
|
||||||
|
TagTrackerItem *item;
|
||||||
|
|
||||||
if(!tagLists[type]) return;
|
if (!tagLists[type])
|
||||||
|
return;
|
||||||
|
|
||||||
node = tagLists[type]->firstNode;
|
node = tagLists[type]->firstNode;
|
||||||
|
|
||||||
while(node) {
|
while (node) {
|
||||||
item = node->data;
|
item = node->data;
|
||||||
if(item->visited) {
|
if (item->visited) {
|
||||||
myfprintf(fp, "%s: %s\n", mpdTagItemKeys[type],
|
myfprintf(fp, "%s: %s\n", mpdTagItemKeys[type],
|
||||||
node->key);
|
node->key);
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@
|
|||||||
|
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
|
|
||||||
char * getTagItemString(int type, char * string);
|
char *getTagItemString(int type, char *string);
|
||||||
|
|
||||||
void removeTagItemString(int type, char * string);
|
void removeTagItemString(int type, char *string);
|
||||||
|
|
||||||
int getNumberOfTagItems(int type);
|
int getNumberOfTagItems(int type);
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ void printMemorySavedByTagTracker();
|
|||||||
|
|
||||||
void resetVisitedFlagsInTagTracker(int type);
|
void resetVisitedFlagsInTagTracker(int type);
|
||||||
|
|
||||||
void visitInTagTracker(int type, char * str);
|
void visitInTagTracker(int type, char *str);
|
||||||
|
|
||||||
void printVisitedInTagTracker(FILE * fp, int type);
|
void printVisitedInTagTracker(FILE * fp, int type);
|
||||||
|
|
||||||
|
105
src/utf8.c
105
src/utf8.c
@ -22,113 +22,126 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static char * latin1ToUtf8(char c) {
|
static char *latin1ToUtf8(char c)
|
||||||
|
{
|
||||||
static unsigned char utf8[3];
|
static unsigned char utf8[3];
|
||||||
unsigned char uc = c;
|
unsigned char uc = c;
|
||||||
|
|
||||||
memset(utf8,0,3);
|
memset(utf8, 0, 3);
|
||||||
|
|
||||||
if(uc < 128) utf8[0] = uc;
|
if (uc < 128)
|
||||||
else if(uc<192) {
|
utf8[0] = uc;
|
||||||
|
else if (uc < 192) {
|
||||||
utf8[0] = 194;
|
utf8[0] = 194;
|
||||||
utf8[1] = uc;
|
utf8[1] = uc;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
utf8[0] = 195;
|
utf8[0] = 195;
|
||||||
utf8[1] = uc-64;
|
utf8[1] = uc - 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (char *)utf8;
|
return (char *)utf8;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * latin1StrToUtf8Dup(char * latin1) {
|
char *latin1StrToUtf8Dup(char *latin1)
|
||||||
|
{
|
||||||
/* utf8 should have at most two char's per latin1 char */
|
/* utf8 should have at most two char's per latin1 char */
|
||||||
int len = strlen(latin1)*2+1;
|
int len = strlen(latin1) * 2 + 1;
|
||||||
char * ret = malloc(len);
|
char *ret = malloc(len);
|
||||||
char * cp = ret;
|
char *cp = ret;
|
||||||
char * utf8;
|
char *utf8;
|
||||||
|
|
||||||
memset(ret,0,len);
|
memset(ret, 0, len);
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
|
|
||||||
while(*latin1) {
|
while (*latin1) {
|
||||||
utf8 = latin1ToUtf8(*latin1);
|
utf8 = latin1ToUtf8(*latin1);
|
||||||
while(*utf8) {
|
while (*utf8) {
|
||||||
*(cp++) = *(utf8++);
|
*(cp++) = *(utf8++);
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
latin1++;
|
latin1++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return realloc(ret,len+1);
|
return realloc(ret, len + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char utf8ToLatin1(char * inUtf8) {
|
static char utf8ToLatin1(char *inUtf8)
|
||||||
|
{
|
||||||
unsigned char c = 0;
|
unsigned char c = 0;
|
||||||
unsigned char * utf8 = (unsigned char *)inUtf8;
|
unsigned char *utf8 = (unsigned char *)inUtf8;
|
||||||
|
|
||||||
if(utf8[0]<128) return utf8[0];
|
if (utf8[0] < 128)
|
||||||
else if(utf8[0]==195) c+=64;
|
return utf8[0];
|
||||||
else if(utf8[0]!=194) return '?';
|
else if (utf8[0] == 195)
|
||||||
return (char)(c+utf8[1]);
|
c += 64;
|
||||||
|
else if (utf8[0] != 194)
|
||||||
|
return '?';
|
||||||
|
return (char)(c + utf8[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int validateUtf8Char(char * inUtf8Char) {
|
static int validateUtf8Char(char *inUtf8Char)
|
||||||
unsigned char * utf8Char = (unsigned char *)inUtf8Char;
|
{
|
||||||
|
unsigned char *utf8Char = (unsigned char *)inUtf8Char;
|
||||||
|
|
||||||
if(utf8Char[0]<0x80) return 1;
|
if (utf8Char[0] < 0x80)
|
||||||
|
return 1;
|
||||||
|
|
||||||
if(utf8Char[0]>=0xC0 && utf8Char[0]<=0xFD) {
|
if (utf8Char[0] >= 0xC0 && utf8Char[0] <= 0xFD) {
|
||||||
int count = 1;
|
int count = 1;
|
||||||
char t = 1 << 5;
|
char t = 1 << 5;
|
||||||
int i;
|
int i;
|
||||||
while(count < 6 && (t & utf8Char[0])) {
|
while (count < 6 && (t & utf8Char[0])) {
|
||||||
t = (t >> 1);
|
t = (t >> 1);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
if(count > 5) return 0;
|
if (count > 5)
|
||||||
for(i=1;i<=count;i++) {
|
return 0;
|
||||||
if(utf8Char[i] < 0x80 || utf8Char[i] > 0xBF) return 0;
|
for (i = 1; i <= count; i++) {
|
||||||
|
if (utf8Char[i] < 0x80 || utf8Char[i] > 0xBF)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return count+1;
|
return count + 1;
|
||||||
}
|
} else
|
||||||
else return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int validUtf8String(char * string) {
|
int validUtf8String(char *string)
|
||||||
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
while(*string) {
|
while (*string) {
|
||||||
ret = validateUtf8Char(string);
|
ret = validateUtf8Char(string);
|
||||||
if(0==ret) return 0;
|
if (0 == ret)
|
||||||
string+= ret;
|
return 0;
|
||||||
|
string += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * utf8StrToLatin1Dup(char * utf8) {
|
char *utf8StrToLatin1Dup(char *utf8)
|
||||||
|
{
|
||||||
/* utf8 should have at most two char's per latin1 char */
|
/* utf8 should have at most two char's per latin1 char */
|
||||||
int len = strlen(utf8)+1;
|
int len = strlen(utf8) + 1;
|
||||||
char * ret = malloc(len);
|
char *ret = malloc(len);
|
||||||
char * cp = ret;
|
char *cp = ret;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
memset(ret,0,len);
|
memset(ret, 0, len);
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
|
|
||||||
while(*utf8) {
|
while (*utf8) {
|
||||||
count = validateUtf8Char(utf8);
|
count = validateUtf8Char(utf8);
|
||||||
if(!count) {
|
if (!count) {
|
||||||
free(ret);
|
free(ret);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
*(cp++) = utf8ToLatin1(utf8);
|
*(cp++) = utf8ToLatin1(utf8);
|
||||||
utf8+= count;
|
utf8 += count;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return realloc(ret,len+1);
|
return realloc(ret, len + 1);
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
#ifndef UTF_8_H
|
#ifndef UTF_8_H
|
||||||
#define UTF_8_H
|
#define UTF_8_H
|
||||||
|
|
||||||
char * latin1StrToUtf8Dup(char * latin1);
|
char *latin1StrToUtf8Dup(char *latin1);
|
||||||
|
|
||||||
char * utf8StrToLatin1Dup(char * utf8);
|
char *utf8StrToLatin1Dup(char *utf8);
|
||||||
|
|
||||||
int validUtf8String(char * string);
|
int validUtf8String(char *string);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
63
src/utils.c
63
src/utils.c
@ -27,75 +27,82 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
char * myFgets(char * buffer, int bufferSize, FILE * fp) {
|
char *myFgets(char *buffer, int bufferSize, FILE * fp)
|
||||||
char * ret = fgets(buffer,bufferSize,fp);
|
{
|
||||||
if(ret && strlen(buffer)>0 && buffer[strlen(buffer)-1]=='\n') {
|
char *ret = fgets(buffer, bufferSize, fp);
|
||||||
buffer[strlen(buffer)-1] = '\0';
|
if (ret && strlen(buffer) > 0 && buffer[strlen(buffer) - 1] == '\n') {
|
||||||
|
buffer[strlen(buffer) - 1] = '\0';
|
||||||
}
|
}
|
||||||
if(ret && strlen(buffer)>0 && buffer[strlen(buffer)-1]=='\r') {
|
if (ret && strlen(buffer) > 0 && buffer[strlen(buffer) - 1] == '\r') {
|
||||||
buffer[strlen(buffer)-1] = '\0';
|
buffer[strlen(buffer) - 1] = '\0';
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * strDupToUpper(char * str) {
|
char *strDupToUpper(char *str)
|
||||||
char * ret = strdup(str);
|
{
|
||||||
|
char *ret = strdup(str);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=0;i<strlen(str);i++) ret[i] = toupper((int)ret[i]);
|
for (i = 0; i < strlen(str); i++)
|
||||||
|
ret[i] = toupper((int)ret[i]);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stripReturnChar(char * string) {
|
void stripReturnChar(char *string)
|
||||||
while(string && (string = strchr(string,'\n'))) {
|
{
|
||||||
|
while (string && (string = strchr(string, '\n'))) {
|
||||||
*string = ' ';
|
*string = ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void my_usleep(long usec) {
|
void my_usleep(long usec)
|
||||||
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
tv.tv_sec = 0;
|
tv.tv_sec = 0;
|
||||||
tv.tv_usec = usec;
|
tv.tv_usec = usec;
|
||||||
|
|
||||||
select(0,NULL,NULL,NULL,&tv);
|
select(0, NULL, NULL, NULL, &tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipv6Supported(void) {
|
int ipv6Supported(void)
|
||||||
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
int s;
|
int s;
|
||||||
s = socket(AF_INET6,SOCK_STREAM,0);
|
s = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
if(s == -1) return 0;
|
if (s == -1)
|
||||||
|
return 0;
|
||||||
close(s);
|
close(s);
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * appendToString(char * dest, const char * src) {
|
char *appendToString(char *dest, const char *src)
|
||||||
|
{
|
||||||
int destlen;
|
int destlen;
|
||||||
int srclen = strlen(src);
|
int srclen = strlen(src);
|
||||||
|
|
||||||
if(dest == NULL) {
|
if (dest == NULL) {
|
||||||
dest = malloc(srclen+1);
|
dest = malloc(srclen + 1);
|
||||||
memset(dest, 0, srclen+1);
|
memset(dest, 0, srclen + 1);
|
||||||
destlen = 0;
|
destlen = 0;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
destlen = strlen(dest);
|
destlen = strlen(dest);
|
||||||
dest = realloc(dest, destlen+srclen+1);
|
dest = realloc(dest, destlen + srclen + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(dest+destlen, src, srclen);
|
memcpy(dest + destlen, src, srclen);
|
||||||
dest[destlen+srclen] = '\0';
|
dest[destlen + srclen] = '\0';
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long readLEuint32(const unsigned char *p)
|
unsigned long readLEuint32(const unsigned char *p)
|
||||||
{
|
{
|
||||||
return ((unsigned long) p[0] << 0) |
|
return ((unsigned long)p[0] << 0) |
|
||||||
((unsigned long) p[1] << 8) |
|
((unsigned long)p[1] << 8) |
|
||||||
((unsigned long) p[2] << 16) | ((unsigned long) p[3] << 24);
|
((unsigned long)p[2] << 16) | ((unsigned long)p[3] << 24);
|
||||||
}
|
}
|
||||||
|
10
src/utils.h
10
src/utils.h
@ -23,18 +23,18 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
char * myFgets(char * buffer, int bufferSize, FILE * fp);
|
char *myFgets(char *buffer, int bufferSize, FILE * fp);
|
||||||
|
|
||||||
char * strDupToUpper(char * str);
|
char *strDupToUpper(char *str);
|
||||||
|
|
||||||
void stripReturnChar(char * string);
|
void stripReturnChar(char *string);
|
||||||
|
|
||||||
void my_usleep(long usec);
|
void my_usleep(long usec);
|
||||||
|
|
||||||
int ipv6Supported();
|
int ipv6Supported();
|
||||||
|
|
||||||
char * appendToString(char * dest, const char * src);
|
char *appendToString(char *dest, const char *src);
|
||||||
|
|
||||||
unsigned long readLEuint32(const unsigned char * p);
|
unsigned long readLEuint32(const unsigned char *p);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
244
src/volume.c
244
src/volume.c
@ -59,7 +59,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int volume_mixerType = VOLUME_MIXER_TYPE_DEFAULT;
|
static int volume_mixerType = VOLUME_MIXER_TYPE_DEFAULT;
|
||||||
static char * volume_mixerDevice = VOLUME_MIXER_DEVICE_DEFAULT;
|
static char *volume_mixerDevice = VOLUME_MIXER_DEVICE_DEFAULT;
|
||||||
|
|
||||||
static int volume_softwareSet = 100;
|
static int volume_softwareSet = 100;
|
||||||
|
|
||||||
@ -69,8 +69,8 @@ static int volume_ossControl = SOUND_MIXER_PCM;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ALSA
|
#ifdef HAVE_ALSA
|
||||||
static snd_mixer_t * volume_alsaMixerHandle = NULL;
|
static snd_mixer_t *volume_alsaMixerHandle = NULL;
|
||||||
static snd_mixer_elem_t * volume_alsaElem;
|
static snd_mixer_elem_t *volume_alsaElem;
|
||||||
static long volume_alsaMin;
|
static long volume_alsaMin;
|
||||||
static long volume_alsaMax;
|
static long volume_alsaMax;
|
||||||
static int volume_alsaSet = -1;
|
static int volume_alsaSet = -1;
|
||||||
@ -80,51 +80,52 @@ static int volume_alsaSet = -1;
|
|||||||
|
|
||||||
static void closeOssMixer(void)
|
static void closeOssMixer(void)
|
||||||
{
|
{
|
||||||
while (close(volume_ossFd) && errno == EINTR);
|
while (close(volume_ossFd) && errno == EINTR) ;
|
||||||
volume_ossFd = -1;
|
volume_ossFd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prepOssMixer(char * device) {
|
static int prepOssMixer(char *device)
|
||||||
ConfigParam * param;
|
{
|
||||||
|
ConfigParam *param;
|
||||||
|
|
||||||
if((volume_ossFd = open(device,O_RDONLY))<0) {
|
if ((volume_ossFd = open(device, O_RDONLY)) < 0) {
|
||||||
WARNING("unable to open oss mixer \"%s\"\n",device);
|
WARNING("unable to open oss mixer \"%s\"\n", device);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
param = getConfigParam(CONF_MIXER_CONTROL);
|
param = getConfigParam(CONF_MIXER_CONTROL);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
char * labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
|
char *labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
|
||||||
char * dup;
|
char *dup;
|
||||||
int i,j;
|
int i, j;
|
||||||
int devmask = 0;
|
int devmask = 0;
|
||||||
|
|
||||||
if(ioctl(volume_ossFd,SOUND_MIXER_READ_DEVMASK,&devmask)<0) {
|
if (ioctl(volume_ossFd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) {
|
||||||
WARNING("errors getting read_devmask for oss mixer\n");
|
WARNING("errors getting read_devmask for oss mixer\n");
|
||||||
closeOssMixer();
|
closeOssMixer();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0;i<SOUND_MIXER_NRDEVICES;i++) {
|
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
|
||||||
dup = strdup(labels[i]);
|
dup = strdup(labels[i]);
|
||||||
/* eliminate spaces at the end */
|
/* eliminate spaces at the end */
|
||||||
j = strlen(dup)-1;
|
j = strlen(dup) - 1;
|
||||||
while(j>=0 && dup[j]==' ') dup[j--] = '\0';
|
while (j >= 0 && dup[j] == ' ')
|
||||||
if(strcasecmp(dup, param->value)==0) {
|
dup[j--] = '\0';
|
||||||
|
if (strcasecmp(dup, param->value) == 0) {
|
||||||
free(dup);
|
free(dup);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
free(dup);
|
free(dup);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(i>=SOUND_MIXER_NRDEVICES) {
|
if (i >= SOUND_MIXER_NRDEVICES) {
|
||||||
WARNING("mixer control \"%s\" not found at line %i\n",
|
WARNING("mixer control \"%s\" not found at line %i\n",
|
||||||
param->value, param->line);
|
param->value, param->line);
|
||||||
closeOssMixer();
|
closeOssMixer();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else if (!((1 << i) & devmask)) {
|
||||||
else if(!( ( 1 << i ) & devmask )) {
|
|
||||||
WARNING("mixer control \"%s\" not usable at line %i\n",
|
WARNING("mixer control \"%s\" not usable at line %i\n",
|
||||||
param->value, param->line);
|
param->value, param->line);
|
||||||
closeOssMixer();
|
closeOssMixer();
|
||||||
@ -144,13 +145,14 @@ static int ensure_oss_open(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getOssVolumeLevel(void) {
|
static int getOssVolumeLevel(void)
|
||||||
|
{
|
||||||
int left, right, level;
|
int left, right, level;
|
||||||
|
|
||||||
if (ensure_oss_open() < 0)
|
if (ensure_oss_open() < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if(ioctl(volume_ossFd,MIXER_READ(volume_ossControl),&level) < 0) {
|
if (ioctl(volume_ossFd, MIXER_READ(volume_ossControl), &level) < 0) {
|
||||||
closeOssMixer();
|
closeOssMixer();
|
||||||
WARNING("unable to read volume\n");
|
WARNING("unable to read volume\n");
|
||||||
return -1;
|
return -1;
|
||||||
@ -159,39 +161,42 @@ static int getOssVolumeLevel(void) {
|
|||||||
left = level & 0xff;
|
left = level & 0xff;
|
||||||
right = (level & 0xff00) >> 8;
|
right = (level & 0xff00) >> 8;
|
||||||
|
|
||||||
if(left!=right) {
|
if (left != right) {
|
||||||
WARNING("volume for left and right is not the same, \"%i\" and "
|
WARNING("volume for left and right is not the same, \"%i\" and "
|
||||||
"\"%i\"\n",left,right);
|
"\"%i\"\n", left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int changeOssVolumeLevel(FILE * fp, int change, int rel) {
|
static int changeOssVolumeLevel(FILE * fp, int change, int rel)
|
||||||
|
{
|
||||||
int current;
|
int current;
|
||||||
int new;
|
int new;
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
if (rel) {
|
if (rel) {
|
||||||
if((current = getOssVolumeLevel()) < 0) {
|
if ((current = getOssVolumeLevel()) < 0) {
|
||||||
commandError(fp, ACK_ERROR_SYSTEM,
|
commandError(fp, ACK_ERROR_SYSTEM,
|
||||||
"problem getting current volume", NULL);
|
"problem getting current volume", NULL);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = current+change;
|
new = current + change;
|
||||||
} else {
|
} else {
|
||||||
if (ensure_oss_open() < 0)
|
if (ensure_oss_open() < 0)
|
||||||
return -1;
|
return -1;
|
||||||
new = change;
|
new = change;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(new<0) new = 0;
|
if (new < 0)
|
||||||
else if(new>100) new = 100;
|
new = 0;
|
||||||
|
else if (new > 100)
|
||||||
|
new = 100;
|
||||||
|
|
||||||
level = (new << 8) + new;
|
level = (new << 8) + new;
|
||||||
|
|
||||||
if(ioctl(volume_ossFd,MIXER_WRITE(volume_ossControl),&level) < 0) {
|
if (ioctl(volume_ossFd, MIXER_WRITE(volume_ossControl), &level) < 0) {
|
||||||
closeOssMixer();
|
closeOssMixer();
|
||||||
commandError(fp, ACK_ERROR_SYSTEM, "problems setting volume",
|
commandError(fp, ACK_ERROR_SYSTEM, "problems setting volume",
|
||||||
NULL);
|
NULL);
|
||||||
@ -203,39 +208,43 @@ static int changeOssVolumeLevel(FILE * fp, int change, int rel) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ALSA
|
#ifdef HAVE_ALSA
|
||||||
static void closeAlsaMixer(void) {
|
static void closeAlsaMixer(void)
|
||||||
|
{
|
||||||
snd_mixer_close(volume_alsaMixerHandle);
|
snd_mixer_close(volume_alsaMixerHandle);
|
||||||
volume_alsaMixerHandle = NULL;
|
volume_alsaMixerHandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prepAlsaMixer(char * card) {
|
static int prepAlsaMixer(char *card)
|
||||||
|
{
|
||||||
int err;
|
int err;
|
||||||
snd_mixer_elem_t * elem;
|
snd_mixer_elem_t *elem;
|
||||||
char * controlName = VOLUME_MIXER_ALSA_CONTROL_DEFAULT;
|
char *controlName = VOLUME_MIXER_ALSA_CONTROL_DEFAULT;
|
||||||
ConfigParam * param;
|
ConfigParam *param;
|
||||||
|
|
||||||
err = snd_mixer_open(&volume_alsaMixerHandle,0);
|
err = snd_mixer_open(&volume_alsaMixerHandle, 0);
|
||||||
snd_config_update_free_global();
|
snd_config_update_free_global();
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
WARNING("problems opening alsa mixer: %s\n",snd_strerror(err));
|
WARNING("problems opening alsa mixer: %s\n", snd_strerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((err = snd_mixer_attach(volume_alsaMixerHandle,card))<0) {
|
if ((err = snd_mixer_attach(volume_alsaMixerHandle, card)) < 0) {
|
||||||
closeAlsaMixer();
|
closeAlsaMixer();
|
||||||
WARNING("problems problems attaching alsa mixer: %s\n",
|
WARNING("problems problems attaching alsa mixer: %s\n",
|
||||||
snd_strerror(err));
|
snd_strerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((err = snd_mixer_selem_register(volume_alsaMixerHandle,NULL,NULL))<0) {
|
if ((err =
|
||||||
|
snd_mixer_selem_register(volume_alsaMixerHandle, NULL,
|
||||||
|
NULL)) < 0) {
|
||||||
closeAlsaMixer();
|
closeAlsaMixer();
|
||||||
WARNING("problems snd_mixer_selem_register'ing: %s\n",
|
WARNING("problems snd_mixer_selem_register'ing: %s\n",
|
||||||
snd_strerror(err));
|
snd_strerror(err));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((err = snd_mixer_load(volume_alsaMixerHandle))<0) {
|
if ((err = snd_mixer_load(volume_alsaMixerHandle)) < 0) {
|
||||||
closeAlsaMixer();
|
closeAlsaMixer();
|
||||||
WARNING("problems snd_mixer_selem_register'ing: %s\n",
|
WARNING("problems snd_mixer_selem_register'ing: %s\n",
|
||||||
snd_strerror(err));
|
snd_strerror(err));
|
||||||
@ -246,30 +255,29 @@ static int prepAlsaMixer(char * card) {
|
|||||||
|
|
||||||
param = getConfigParam(CONF_MIXER_CONTROL);
|
param = getConfigParam(CONF_MIXER_CONTROL);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
controlName = param->value;
|
controlName = param->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(elem) {
|
while (elem) {
|
||||||
if(snd_mixer_elem_get_type(elem)==SND_MIXER_ELEM_SIMPLE) {
|
if (snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE) {
|
||||||
if(strcasecmp(controlName,
|
if (strcasecmp(controlName,
|
||||||
snd_mixer_selem_get_name(elem))==0)
|
snd_mixer_selem_get_name(elem)) == 0) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elem = snd_mixer_elem_next(elem);
|
elem = snd_mixer_elem_next(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(elem) {
|
if (elem) {
|
||||||
volume_alsaElem = elem;
|
volume_alsaElem = elem;
|
||||||
snd_mixer_selem_get_playback_volume_range(
|
snd_mixer_selem_get_playback_volume_range(volume_alsaElem,
|
||||||
volume_alsaElem,
|
&volume_alsaMin,
|
||||||
&volume_alsaMin,&volume_alsaMax);
|
&volume_alsaMax);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
WARNING("can't find alsa mixer_control \"%s\"\n",controlName);
|
WARNING("can't find alsa mixer_control \"%s\"\n", controlName);
|
||||||
|
|
||||||
closeAlsaMixer();
|
closeAlsaMixer();
|
||||||
return -1;
|
return -1;
|
||||||
@ -280,27 +288,29 @@ static int prep_alsa_get_level(long *level)
|
|||||||
const char *cmd;
|
const char *cmd;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!volume_alsaMixerHandle && prepAlsaMixer(volume_mixerDevice)<0)
|
if (!volume_alsaMixerHandle && prepAlsaMixer(volume_mixerDevice) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if ((err = snd_mixer_handle_events(volume_alsaMixerHandle)) < 0) {
|
if ((err = snd_mixer_handle_events(volume_alsaMixerHandle)) < 0) {
|
||||||
cmd = "handle_events";
|
cmd = "handle_events";
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if((err = snd_mixer_selem_get_playback_volume(volume_alsaElem,
|
if ((err = snd_mixer_selem_get_playback_volume(volume_alsaElem,
|
||||||
SND_MIXER_SCHN_FRONT_LEFT, level)) < 0) {
|
SND_MIXER_SCHN_FRONT_LEFT,
|
||||||
|
level)) < 0) {
|
||||||
cmd = "selem_get_playback_volume";
|
cmd = "selem_get_playback_volume";
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
error:
|
||||||
WARNING("problems getting alsa volume: %s (snd_mixer_%s)\n",
|
WARNING("problems getting alsa volume: %s (snd_mixer_%s)\n",
|
||||||
snd_strerror(err), cmd);
|
snd_strerror(err), cmd);
|
||||||
closeAlsaMixer();
|
closeAlsaMixer();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getAlsaVolumeLevel(void) {
|
static int getAlsaVolumeLevel(void)
|
||||||
|
{
|
||||||
int ret;
|
int ret;
|
||||||
long level;
|
long level;
|
||||||
long max = volume_alsaMax;
|
long max = volume_alsaMax;
|
||||||
@ -309,16 +319,17 @@ static int getAlsaVolumeLevel(void) {
|
|||||||
if (prep_alsa_get_level(&level) < 0)
|
if (prep_alsa_get_level(&level) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = ((volume_alsaSet/100.0)*(max-min)+min)+0.5;
|
ret = ((volume_alsaSet / 100.0) * (max - min) + min) + 0.5;
|
||||||
if(volume_alsaSet>0 && ret==level) {
|
if (volume_alsaSet > 0 && ret == level) {
|
||||||
ret = volume_alsaSet;
|
ret = volume_alsaSet;
|
||||||
}
|
} else
|
||||||
else ret = (int)(100*(((float)(level-min))/(max-min))+0.5);
|
ret = (int)(100 * (((float)(level - min)) / (max - min)) + 0.5);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int changeAlsaVolumeLevel(FILE * fp, int change, int rel) {
|
static int changeAlsaVolumeLevel(FILE * fp, int change, int rel)
|
||||||
|
{
|
||||||
float vol;
|
float vol;
|
||||||
long level;
|
long level;
|
||||||
long test;
|
long test;
|
||||||
@ -330,29 +341,30 @@ static int changeAlsaVolumeLevel(FILE * fp, int change, int rel) {
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (rel) {
|
if (rel) {
|
||||||
test = ((volume_alsaSet/100.0)*(max-min)+min)+0.5;
|
test = ((volume_alsaSet / 100.0) * (max - min) + min) + 0.5;
|
||||||
if(volume_alsaSet >= 0 && level==test) {
|
if (volume_alsaSet >= 0 && level == test) {
|
||||||
vol = volume_alsaSet;
|
vol = volume_alsaSet;
|
||||||
}
|
} else
|
||||||
else vol = 100.0*(((float)(level-min))/(max-min));
|
vol = 100.0 * (((float)(level - min)) / (max - min));
|
||||||
vol+=change;
|
vol += change;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
vol = change;
|
vol = change;
|
||||||
|
|
||||||
volume_alsaSet = vol+0.5;
|
volume_alsaSet = vol + 0.5;
|
||||||
volume_alsaSet = volume_alsaSet>100 ? 100 :
|
volume_alsaSet = volume_alsaSet > 100 ? 100 :
|
||||||
(volume_alsaSet<0 ? 0 : volume_alsaSet);
|
(volume_alsaSet < 0 ? 0 : volume_alsaSet);
|
||||||
|
|
||||||
level = (long)(((vol/100.0)*(max-min)+min)+0.5);
|
level = (long)(((vol / 100.0) * (max - min) + min) + 0.5);
|
||||||
level = level>max?max:level;
|
level = level > max ? max : level;
|
||||||
level = level<min?min:level;
|
level = level < min ? min : level;
|
||||||
|
|
||||||
if((err = snd_mixer_selem_set_playback_volume_all(
|
if ((err =
|
||||||
volume_alsaElem,level))<0) {
|
snd_mixer_selem_set_playback_volume_all(volume_alsaElem,
|
||||||
|
level)) < 0) {
|
||||||
commandError(fp, ACK_ERROR_SYSTEM, "problems setting volume",
|
commandError(fp, ACK_ERROR_SYSTEM, "problems setting volume",
|
||||||
NULL);
|
NULL);
|
||||||
WARNING("problems setting alsa volume: %s\n",snd_strerror(err));
|
WARNING("problems setting alsa volume: %s\n",
|
||||||
|
snd_strerror(err));
|
||||||
closeAlsaMixer();
|
closeAlsaMixer();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -361,8 +373,9 @@ static int changeAlsaVolumeLevel(FILE * fp, int change, int rel) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int prepMixer(char * device) {
|
static int prepMixer(char *device)
|
||||||
switch(volume_mixerType) {
|
{
|
||||||
|
switch (volume_mixerType) {
|
||||||
#ifdef HAVE_ALSA
|
#ifdef HAVE_ALSA
|
||||||
case VOLUME_MIXER_TYPE_ALSA:
|
case VOLUME_MIXER_TYPE_ALSA:
|
||||||
return prepAlsaMixer(device);
|
return prepAlsaMixer(device);
|
||||||
@ -376,8 +389,9 @@ static int prepMixer(char * device) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void finishVolume(void) {
|
void finishVolume(void)
|
||||||
switch(volume_mixerType) {
|
{
|
||||||
|
switch (volume_mixerType) {
|
||||||
#ifdef HAVE_ALSA
|
#ifdef HAVE_ALSA
|
||||||
case VOLUME_MIXER_TYPE_ALSA:
|
case VOLUME_MIXER_TYPE_ALSA:
|
||||||
closeAlsaMixer();
|
closeAlsaMixer();
|
||||||
@ -391,28 +405,28 @@ void finishVolume(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initVolume(void) {
|
void initVolume(void)
|
||||||
ConfigParam * param = getConfigParam(CONF_MIXER_TYPE);
|
{
|
||||||
|
ConfigParam *param = getConfigParam(CONF_MIXER_TYPE);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
if(0);
|
if (0) ;
|
||||||
#ifdef HAVE_ALSA
|
#ifdef HAVE_ALSA
|
||||||
else if(strcmp(param->value, VOLUME_MIXER_ALSA)==0) {
|
else if (strcmp(param->value, VOLUME_MIXER_ALSA) == 0) {
|
||||||
volume_mixerType = VOLUME_MIXER_TYPE_ALSA;
|
volume_mixerType = VOLUME_MIXER_TYPE_ALSA;
|
||||||
volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT;
|
volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_OSS
|
#ifdef HAVE_OSS
|
||||||
else if(strcmp(param->value, VOLUME_MIXER_OSS)==0) {
|
else if (strcmp(param->value, VOLUME_MIXER_OSS) == 0) {
|
||||||
volume_mixerType = VOLUME_MIXER_TYPE_OSS;
|
volume_mixerType = VOLUME_MIXER_TYPE_OSS;
|
||||||
volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT;
|
volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if(strcmp(param->value ,VOLUME_MIXER_SOFTWARE)==0) {
|
else if (strcmp(param->value, VOLUME_MIXER_SOFTWARE) == 0) {
|
||||||
volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
|
volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
|
||||||
volume_mixerDevice = VOLUME_MIXER_SOFTWARE_DEFAULT;
|
volume_mixerDevice = VOLUME_MIXER_SOFTWARE_DEFAULT;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ERROR("unknown mixer type %s at line %i\n",
|
ERROR("unknown mixer type %s at line %i\n",
|
||||||
param->value, param->line);
|
param->value, param->line);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -421,24 +435,27 @@ void initVolume(void) {
|
|||||||
|
|
||||||
param = getConfigParam(CONF_MIXER_DEVICE);
|
param = getConfigParam(CONF_MIXER_DEVICE);
|
||||||
|
|
||||||
if(param) {
|
if (param) {
|
||||||
volume_mixerDevice = param->value;
|
volume_mixerDevice = param->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void openVolumeDevice(void) {
|
void openVolumeDevice(void)
|
||||||
if(prepMixer(volume_mixerDevice)<0) {
|
{
|
||||||
|
if (prepMixer(volume_mixerDevice) < 0) {
|
||||||
WARNING("using software volume\n");
|
WARNING("using software volume\n");
|
||||||
volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
|
volume_mixerType = VOLUME_MIXER_TYPE_SOFTWARE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getSoftwareVolume(void) {
|
static int getSoftwareVolume(void)
|
||||||
|
{
|
||||||
return volume_softwareSet;
|
return volume_softwareSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getVolumeLevel(void) {
|
int getVolumeLevel(void)
|
||||||
switch(volume_mixerType) {
|
{
|
||||||
|
switch (volume_mixerType) {
|
||||||
#ifdef HAVE_ALSA
|
#ifdef HAVE_ALSA
|
||||||
case VOLUME_MIXER_TYPE_ALSA:
|
case VOLUME_MIXER_TYPE_ALSA:
|
||||||
return getAlsaVolumeLevel();
|
return getAlsaVolumeLevel();
|
||||||
@ -454,38 +471,47 @@ int getVolumeLevel(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int changeSoftwareVolume(FILE * fp, int change, int rel) {
|
static int changeSoftwareVolume(FILE * fp, int change, int rel)
|
||||||
|
{
|
||||||
int new = change;
|
int new = change;
|
||||||
|
|
||||||
if(rel) new+=volume_softwareSet;
|
if (rel)
|
||||||
|
new += volume_softwareSet;
|
||||||
|
|
||||||
if(new>100) new = 100;
|
if (new > 100)
|
||||||
else if(new<0) new = 0;
|
new = 100;
|
||||||
|
else if (new < 0)
|
||||||
|
new = 0;
|
||||||
|
|
||||||
volume_softwareSet = new;
|
volume_softwareSet = new;
|
||||||
|
|
||||||
/*new = 100.0*(exp(new/50.0)-1)/(M_E*M_E-1)+0.5;*/
|
/*new = 100.0*(exp(new/50.0)-1)/(M_E*M_E-1)+0.5; */
|
||||||
if(new>=100) new = 1000;
|
if (new >= 100)
|
||||||
else if(new<=0) new = 0;
|
new = 1000;
|
||||||
else new = 1000.0*(exp(new/25.0)-1)/(54.5981500331F-1)+0.5;
|
else if (new <= 0)
|
||||||
|
new = 0;
|
||||||
|
else
|
||||||
|
new =
|
||||||
|
1000.0 * (exp(new / 25.0) - 1) / (54.5981500331F - 1) + 0.5;
|
||||||
|
|
||||||
setPlayerSoftwareVolume(new);
|
setPlayerSoftwareVolume(new);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int changeVolumeLevel(FILE * fp, int change, int rel) {
|
int changeVolumeLevel(FILE * fp, int change, int rel)
|
||||||
switch(volume_mixerType) {
|
{
|
||||||
|
switch (volume_mixerType) {
|
||||||
#ifdef HAVE_ALSA
|
#ifdef HAVE_ALSA
|
||||||
case VOLUME_MIXER_TYPE_ALSA:
|
case VOLUME_MIXER_TYPE_ALSA:
|
||||||
return changeAlsaVolumeLevel(fp,change,rel);
|
return changeAlsaVolumeLevel(fp, change, rel);
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_OSS
|
#ifdef HAVE_OSS
|
||||||
case VOLUME_MIXER_TYPE_OSS:
|
case VOLUME_MIXER_TYPE_OSS:
|
||||||
return changeOssVolumeLevel(fp,change,rel);
|
return changeOssVolumeLevel(fp, change, rel);
|
||||||
#endif
|
#endif
|
||||||
case VOLUME_MIXER_TYPE_SOFTWARE:
|
case VOLUME_MIXER_TYPE_SOFTWARE:
|
||||||
return changeSoftwareVolume(fp,change,rel);
|
return changeSoftwareVolume(fp, change, rel);
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user