aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/audio.c48
-rw-r--r--src/audio.h2
-rw-r--r--src/audioOutput_shout.c88
-rw-r--r--src/conf.c5
-rw-r--r--src/conf.h1
-rw-r--r--src/outputBuffer.c2
-rw-r--r--src/pcm_utils.c75
-rw-r--r--src/pcm_utils.h2
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: */