diff options
Diffstat (limited to '')
-rw-r--r-- | src/audio.c | 48 | ||||
-rw-r--r-- | src/audio.h | 2 | ||||
-rw-r--r-- | src/audioOutput_shout.c | 88 | ||||
-rw-r--r-- | src/conf.c | 5 | ||||
-rw-r--r-- | src/conf.h | 1 | ||||
-rw-r--r-- | src/outputBuffer.c | 2 | ||||
-rw-r--r-- | src/pcm_utils.c | 75 | ||||
-rw-r--r-- | src/pcm_utils.h | 2 |
8 files changed, 167 insertions, 56 deletions
diff --git a/src/audio.c b/src/audio.c index f8bcd7edc..75d833be3 100644 --- a/src/audio.c +++ b/src/audio.c @@ -66,22 +66,27 @@ void getOutputAudioFormat(AudioFormat * inAudioFormat, void initAudioConfig() { char * conf = getConf()[CONF_AUDIO_OUTPUT_FORMAT]; - char * test; if(NULL == conf) return; audio_configFormat = malloc(sizeof(AudioFormat)); - memset(audio_configFormat,0,sizeof(AudioFormat)); + if(0 != parseAudioConfig(audio_configFormat, conf)) exit(EXIT_FAILURE); +} + +int parseAudioConfig(AudioFormat * audioFormat, char * conf) { + char * test; - audio_configFormat->sampleRate = strtol(conf,&test,10); + memset(audioFormat,0,sizeof(AudioFormat)); + + audioFormat->sampleRate = strtol(conf,&test,10); if(*test!=':') { ERROR("error parsing audio output format: %s\n",conf); - exit(EXIT_FAILURE); + return -1; } - /*switch(audio_configFormat->sampleRate) { + /*switch(audioFormat->sampleRate) { case 48000: case 44100: case 32000: @@ -89,47 +94,50 @@ void initAudioConfig() { break; default: ERROR("sample rate %i can not be used for audio output\n", - (int)audio_configFormat->sampleRate); - exit(EXIT_FAILURE); + (int)audioFormat->sampleRate); + return -1 }*/ - if(audio_configFormat->sampleRate <= 0) { + if(audioFormat->sampleRate <= 0) { ERROR("sample rate %i is not >= 0\n", - (int)audio_configFormat->sampleRate); - exit(EXIT_FAILURE); + (int)audioFormat->sampleRate); + return -1; } - audio_configFormat->bits = strtol(test+1,&test,10); + audioFormat->bits = strtol(test+1,&test,10); if(*test!=':') { ERROR("error parsing audio output format: %s\n",conf); - exit(EXIT_FAILURE); + return -1; } - switch(audio_configFormat->bits) { + switch(audioFormat->bits) { case 16: break; default: ERROR("bits %i can not be used for audio output\n", - (int)audio_configFormat->bits); - exit(EXIT_FAILURE); + (int)audioFormat->bits); + return -1; } - audio_configFormat->channels = strtol(test+1,&test,10); + audioFormat->channels = strtol(test+1,&test,10); if(*test!='\0') { ERROR("error parsing audio output format: %s\n",conf); - exit(EXIT_FAILURE); + return -1; } - switch(audio_configFormat->channels) { + switch(audioFormat->channels) { + case 1: case 2: break; default: ERROR("channels %i can not be used for audio output\n", - (int)audio_configFormat->channels); - exit(EXIT_FAILURE); + (int)audioFormat->channels); + return -1; } + + return 0; } void finishAudioConfig() { diff --git a/src/audio.h b/src/audio.h index 478b6946e..7a1209c1b 100644 --- a/src/audio.h +++ b/src/audio.h @@ -35,6 +35,8 @@ typedef struct _AudioFormat { void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat); +int parseAudioConfig(AudioFormat * audioFormat, char * conf); + void initAudioConfig(); void finishAudioConfig(); diff --git a/src/audioOutput_shout.c b/src/audioOutput_shout.c index fdf1937a4..628483d21 100644 --- a/src/audioOutput_shout.c +++ b/src/audioOutput_shout.c @@ -24,6 +24,7 @@ #include "conf.h" #include "log.h" #include "sig_handlers.h" +#include "pcm_utils.h" #include <stdlib.h> #include <string.h> @@ -54,6 +55,15 @@ typedef struct _ShoutData { vorbis_comment vc; int serialno; + + float quality; + AudioFormat outAudioFormat; + AudioFormat inAudioFormat; + + char * convBuffer; + long convBufferLen; + /* shoud we convert the audio to a different format? */ + int audioFormatConvert; } ShoutData; static ShoutData * newShoutData() { @@ -61,6 +71,8 @@ static ShoutData * newShoutData() { ret->shoutConn = shout_new(); ret->serialno = rand(); + ret->convBuffer = NULL; + ret->convBufferLen = 0; return ret; } @@ -112,6 +124,16 @@ static int shout_initDriver(AudioOutput * audioOutput) { exit(EXIT_FAILURE); } + if(!getConf()[CONF_SHOUT_QUALITY]) { + ERROR("shout host defined but not shout quality\n"); + exit(EXIT_FAILURE); + } + + if(!getConf()[CONF_SHOUT_FORMAT]) { + ERROR("shout host defined but not shout format\n"); + exit(EXIT_FAILURE); + } + host = getConf()[CONF_SHOUT_HOST]; passwd = getConf()[CONF_SHOUT_PASSWD]; user = getConf()[CONF_SHOUT_USER]; @@ -126,6 +148,20 @@ static int shout_initDriver(AudioOutput * audioOutput) { exit(EXIT_FAILURE); } + sd->quality = strtod(getConf()[CONF_SHOUT_QUALITY], &test); + + if(*test != '\0' || sd->quality < 0.0 || sd->quality > 10.0) { + ERROR("shout quality \"%s\" is not a number in the range " + "0-10\n", getConf()[CONF_SHOUT_QUALITY]); + exit(EXIT_FAILURE); + } + + if(0 != parseAudioConfig(&(sd->outAudioFormat), + getConf()[CONF_SHOUT_FORMAT]) ) + { + exit(EXIT_FAILURE); + } + if(shout_set_host(sd->shoutConn, host) != SHOUTERR_SUCCESS || shout_set_port(sd->shoutConn, port) != SHOUTERR_SUCCESS || shout_set_password(sd->shoutConn, passwd) != SHOUTERR_SUCCESS || @@ -202,8 +238,8 @@ static int shout_openDevice(AudioOutput * audioOutput, vorbis_info_init(&(sd->vi)); - if( 0 != vorbis_encode_init_vbr(&(sd->vi), audioFormat->channels, - audioFormat->sampleRate, 0.5) ) + if( 0 != vorbis_encode_init_vbr(&(sd->vi), sd->outAudioFormat.channels, + sd->outAudioFormat.sampleRate, sd->quality) ) { ERROR("problem seting up vorbis encoder for shout\n"); vorbis_info_clear(&(sd->vi)); @@ -230,19 +266,59 @@ static int shout_openDevice(AudioOutput * audioOutput, write_page(sd); } + memcpy(&(sd->inAudioFormat), audioFormat, sizeof(AudioFormat)); + + if(0 == memcmp(&(sd->inAudioFormat), &(sd->outAudioFormat), + sizeof(AudioFormat))) + { + sd->audioFormatConvert = 0; + } + else sd->audioFormatConvert = 1; + return 0; } +static void shout_convertAudioFormat(ShoutData * sd, char ** chunkArgPtr, + int * sizeArgPtr) +{ + int size = pcm_sizeOfOutputBufferForAudioFormatConversion( + &(sd->inAudioFormat), *sizeArgPtr, + &(sd->outAudioFormat)); + + if(size > sd->convBufferLen) { + sd->convBuffer = realloc(sd->convBuffer, size); + sd->convBufferLen = size; + } + + pcm_convertAudioFormat(&(sd->inAudioFormat), *chunkArgPtr, *sizeArgPtr, + &(sd->outAudioFormat), sd->convBuffer); + + *sizeArgPtr = size; + *chunkArgPtr = sd->convBuffer; +} static int shout_play(AudioOutput * audioOutput, char * playChunk, int size) { int i,j; ShoutData * sd = (ShoutData *)audioOutput->data; + float ** vorbbuf; + int samples; + int bytes = sd->outAudioFormat.bits/8; + + if(sd->audioFormatConvert) { + shout_convertAudioFormat(sd, &playChunk, &size); + } - float **vorbbuf = vorbis_analysis_buffer(&(sd->vd), size/4); + samples = size/(bytes*sd->outAudioFormat.channels); - for(i=0, j=0; i < size; i+=4, j++) { - vorbbuf[0][j] = (*((mpd_sint16 *)(playChunk+i))) / 32768.0; - vorbbuf[1][j] = (*((mpd_sint16 *)(playChunk+i+2))) / 32768.0; + /* this is for only 16-bit audio */ + + vorbbuf = vorbis_analysis_buffer(&(sd->vd), samples); + + for(i=0; i<samples; i++) { + for(j=0; j<sd->outAudioFormat.channels; j++) { + vorbbuf[j][i] = (*((mpd_sint16 *)playChunk)) / 32768.0; + playChunk += bytes; + } } vorbis_analysis_wrote(&(sd->vd), size/4); diff --git a/src/conf.c b/src/conf.c index d61d638bf..a89a1e334 100644 --- a/src/conf.c +++ b/src/conf.c @@ -37,7 +37,7 @@ #define CONF_COMMENT '#' -#define CONF_NUMBER_OF_PARAMS 42 +#define CONF_NUMBER_OF_PARAMS 43 #define CONF_NUMBER_OF_PATHS 6 #define CONF_NUMBER_OF_REQUIRED 5 #define CONF_NUMBER_OF_ALLOW_CATS 1 @@ -138,7 +138,8 @@ char ** readConf(char * file) { "shout_name", "shout_user", "shout_quality", - "id3v1_encoding" + "id3v1_encoding", + "shout_format" }; int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = { diff --git a/src/conf.h b/src/conf.h index d87dc24fc..f6bd5d283 100644 --- a/src/conf.h +++ b/src/conf.h @@ -63,6 +63,7 @@ #define CONF_SHOUT_USER 39 #define CONF_SHOUT_QUALITY 40 #define CONF_ID3V1_ENCODING 41 +#define CONF_SHOUT_FORMAT 42 #define CONF_CAT_CHAR "\n" diff --git a/src/outputBuffer.c b/src/outputBuffer.c index 8e4c2d93e..cd7336a8b 100644 --- a/src/outputBuffer.c +++ b/src/outputBuffer.c @@ -80,7 +80,7 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, } else { datalen = pcm_sizeOfOutputBufferForAudioFormatConversion( - &(dc->audioFormat), dataIn, dataInLen, + &(dc->audioFormat), dataInLen, &(cb->audioFormat)); if(datalen > convBufferLen) { convBuffer = realloc(convBuffer,datalen); diff --git a/src/pcm_utils.c b/src/pcm_utils.c index e9beeeead..b3191a399 100644 --- a/src/pcm_utils.c +++ b/src/pcm_utils.c @@ -153,7 +153,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t int dataBitLen; assert(outFormat->bits==16); - assert(outFormat->channels==2); + assert(outFormat->channels==2 || outFormat->channels==1); /* converts */ switch(inFormat->bits) { @@ -185,32 +185,55 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t } /* converts only between 16 bit audio between mono and stereo */ - switch(inFormat->channels) { - case 1: - dataChannelLen = (dataBitLen >> 1) << 2; - if(dataChannelLen > channelConvBufferLength) { - channelConvBuffer = realloc(channelConvBuffer, - dataChannelLen); - channelConvBufferLength = dataChannelLen; - } - dataChannelConv = channelConvBuffer; - { - mpd_sint16 * in = (mpd_sint16 *)dataBitConv; - mpd_sint16 * out = (mpd_sint16 *)dataChannelConv; - int i, inSamples = dataBitLen >> 1; - for(i=0;i<inSamples;i++) { - *out++ = *in; - *out++ = *in++; - } - } - break; - case 2: + if(inFormat->channels == outFormat->channels) + { dataChannelConv = dataBitConv; dataChannelLen = dataBitLen; - break; - default: - ERROR("only 1 or 2 channels are supported for conversion!\n"); - exit(EXIT_FAILURE); + } + else { + switch(inFormat->channels) { + /* convert from 1 -> 2 channels */ + case 1: + dataChannelLen = (dataBitLen >> 1) << 2; + if(dataChannelLen > channelConvBufferLength) { + channelConvBuffer = realloc(channelConvBuffer, + dataChannelLen); + channelConvBufferLength = dataChannelLen; + } + dataChannelConv = channelConvBuffer; + { + mpd_sint16 * in = (mpd_sint16 *)dataBitConv; + mpd_sint16 * out = (mpd_sint16 *)dataChannelConv; + int i, inSamples = dataBitLen >> 1; + for(i=0;i<inSamples;i++) { + *out++ = *in; + *out++ = *in++; + } + } + break; + /* convert from 2 -> 1 channels */ + case 2: + dataChannelLen = dataBitLen >> 1; + if(dataChannelLen > channelConvBufferLength) { + channelConvBuffer = realloc(channelConvBuffer, + dataChannelLen); + channelConvBufferLength = dataChannelLen; + } + dataChannelConv = channelConvBuffer; + { + mpd_sint16 * in = (mpd_sint16 *)dataBitConv; + mpd_sint16 * out = (mpd_sint16 *)dataChannelConv; + int i, inSamples = dataBitLen >> 2; + for(i=0;i<inSamples;i++) { + *out = (*in++)/2; + *out++ += (*in++)/2; + } + } + break; + default: + ERROR("only 1 or 2 channels are supported for conversion!\n"); + exit(EXIT_FAILURE); + } } if(inFormat->sampleRate == outFormat->sampleRate) { @@ -247,7 +270,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t } size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat, - char * inBuffer, size_t inSize, AudioFormat * outFormat) + size_t inSize, AudioFormat * outFormat) { const int shift = sizeof(mpd_sint16); size_t outSize = inSize; diff --git a/src/pcm_utils.h b/src/pcm_utils.h index bf1e68799..73002e32e 100644 --- a/src/pcm_utils.h +++ b/src/pcm_utils.h @@ -37,6 +37,6 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t inSize, AudioFormat * outFormat, char * outBuffer); size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat, - char * inBuffer, size_t inSize, AudioFormat * outFormat); + size_t inSize, AudioFormat * outFormat); #endif /* vim:set shiftwidth=8 tabstop=8 expandtab: */ |