configure shout encoding quality and audio format

git-svn-id: https://svn.musicpd.org/mpd/trunk@2307 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
Warren Dukes 2004-10-23 01:04:58 +00:00
parent 413bf61ea1
commit 12597322a2
8 changed files with 167 additions and 56 deletions

View File

@ -66,22 +66,27 @@ void getOutputAudioFormat(AudioFormat * inAudioFormat,
void initAudioConfig() { void initAudioConfig() {
char * conf = getConf()[CONF_AUDIO_OUTPUT_FORMAT]; char * conf = getConf()[CONF_AUDIO_OUTPUT_FORMAT];
char * test;
if(NULL == conf) return; if(NULL == conf) return;
audio_configFormat = malloc(sizeof(AudioFormat)); audio_configFormat = malloc(sizeof(AudioFormat));
memset(audio_configFormat,0,sizeof(AudioFormat)); if(0 != parseAudioConfig(audio_configFormat, conf)) exit(EXIT_FAILURE);
}
audio_configFormat->sampleRate = strtol(conf,&test,10); int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
char * test;
memset(audioFormat,0,sizeof(AudioFormat));
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);
exit(EXIT_FAILURE); return -1;
} }
/*switch(audio_configFormat->sampleRate) { /*switch(audioFormat->sampleRate) {
case 48000: case 48000:
case 44100: case 44100:
case 32000: case 32000:
@ -89,47 +94,50 @@ void initAudioConfig() {
break; break;
default: default:
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)audio_configFormat->sampleRate); (int)audioFormat->sampleRate);
exit(EXIT_FAILURE); return -1
}*/ }*/
if(audio_configFormat->sampleRate <= 0) { if(audioFormat->sampleRate <= 0) {
ERROR("sample rate %i is not >= 0\n", ERROR("sample rate %i is not >= 0\n",
(int)audio_configFormat->sampleRate); (int)audioFormat->sampleRate);
exit(EXIT_FAILURE); return -1;
} }
audio_configFormat->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);
exit(EXIT_FAILURE); return -1;
} }
switch(audio_configFormat->bits) { switch(audioFormat->bits) {
case 16: case 16:
break; break;
default: default:
ERROR("bits %i can not be used for audio output\n", ERROR("bits %i can not be used for audio output\n",
(int)audio_configFormat->bits); (int)audioFormat->bits);
exit(EXIT_FAILURE); return -1;
} }
audio_configFormat->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);
exit(EXIT_FAILURE); return -1;
} }
switch(audio_configFormat->channels) { switch(audioFormat->channels) {
case 1:
case 2: case 2:
break; break;
default: default:
ERROR("channels %i can not be used for audio output\n", ERROR("channels %i can not be used for audio output\n",
(int)audio_configFormat->channels); (int)audioFormat->channels);
exit(EXIT_FAILURE); return -1;
} }
return 0;
} }
void finishAudioConfig() { void finishAudioConfig() {

View File

@ -35,6 +35,8 @@ typedef struct _AudioFormat {
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat); void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
int parseAudioConfig(AudioFormat * audioFormat, char * conf);
void initAudioConfig(); void initAudioConfig();
void finishAudioConfig(); void finishAudioConfig();

View File

@ -24,6 +24,7 @@
#include "conf.h" #include "conf.h"
#include "log.h" #include "log.h"
#include "sig_handlers.h" #include "sig_handlers.h"
#include "pcm_utils.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -54,6 +55,15 @@ typedef struct _ShoutData {
vorbis_comment vc; vorbis_comment vc;
int serialno; int serialno;
float quality;
AudioFormat outAudioFormat;
AudioFormat inAudioFormat;
char * convBuffer;
long convBufferLen;
/* shoud we convert the audio to a different format? */
int audioFormatConvert;
} ShoutData; } ShoutData;
static ShoutData * newShoutData() { static ShoutData * newShoutData() {
@ -61,6 +71,8 @@ static ShoutData * newShoutData() {
ret->shoutConn = shout_new(); ret->shoutConn = shout_new();
ret->serialno = rand(); ret->serialno = rand();
ret->convBuffer = NULL;
ret->convBufferLen = 0;
return ret; return ret;
} }
@ -112,6 +124,16 @@ static int shout_initDriver(AudioOutput * audioOutput) {
exit(EXIT_FAILURE); 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]; host = getConf()[CONF_SHOUT_HOST];
passwd = getConf()[CONF_SHOUT_PASSWD]; passwd = getConf()[CONF_SHOUT_PASSWD];
user = getConf()[CONF_SHOUT_USER]; user = getConf()[CONF_SHOUT_USER];
@ -126,6 +148,20 @@ static int shout_initDriver(AudioOutput * audioOutput) {
exit(EXIT_FAILURE); 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 || 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 ||
@ -202,8 +238,8 @@ static int shout_openDevice(AudioOutput * audioOutput,
vorbis_info_init(&(sd->vi)); vorbis_info_init(&(sd->vi));
if( 0 != vorbis_encode_init_vbr(&(sd->vi), audioFormat->channels, if( 0 != vorbis_encode_init_vbr(&(sd->vi), sd->outAudioFormat.channels,
audioFormat->sampleRate, 0.5) ) sd->outAudioFormat.sampleRate, sd->quality) )
{ {
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));
@ -230,19 +266,59 @@ static int shout_openDevice(AudioOutput * audioOutput,
write_page(sd); 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; 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) { static int shout_play(AudioOutput * audioOutput, char * playChunk, int size) {
int i,j; int i,j;
ShoutData * sd = (ShoutData *)audioOutput->data; ShoutData * sd = (ShoutData *)audioOutput->data;
float ** vorbbuf;
int samples;
int bytes = sd->outAudioFormat.bits/8;
float **vorbbuf = vorbis_analysis_buffer(&(sd->vd), size/4); if(sd->audioFormatConvert) {
shout_convertAudioFormat(sd, &playChunk, &size);
}
for(i=0, j=0; i < size; i+=4, j++) { samples = size/(bytes*sd->outAudioFormat.channels);
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); vorbis_analysis_wrote(&(sd->vd), size/4);

View File

@ -37,7 +37,7 @@
#define CONF_COMMENT '#' #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_PATHS 6
#define CONF_NUMBER_OF_REQUIRED 5 #define CONF_NUMBER_OF_REQUIRED 5
#define CONF_NUMBER_OF_ALLOW_CATS 1 #define CONF_NUMBER_OF_ALLOW_CATS 1
@ -138,7 +138,8 @@ char ** readConf(char * file) {
"shout_name", "shout_name",
"shout_user", "shout_user",
"shout_quality", "shout_quality",
"id3v1_encoding" "id3v1_encoding",
"shout_format"
}; };
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = { int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {

View File

@ -63,6 +63,7 @@
#define CONF_SHOUT_USER 39 #define CONF_SHOUT_USER 39
#define CONF_SHOUT_QUALITY 40 #define CONF_SHOUT_QUALITY 40
#define CONF_ID3V1_ENCODING 41 #define CONF_ID3V1_ENCODING 41
#define CONF_SHOUT_FORMAT 42
#define CONF_CAT_CHAR "\n" #define CONF_CAT_CHAR "\n"

View File

@ -80,7 +80,7 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
} }
else { else {
datalen = pcm_sizeOfOutputBufferForAudioFormatConversion( datalen = pcm_sizeOfOutputBufferForAudioFormatConversion(
&(dc->audioFormat), dataIn, dataInLen, &(dc->audioFormat), dataInLen,
&(cb->audioFormat)); &(cb->audioFormat));
if(datalen > convBufferLen) { if(datalen > convBufferLen) {
convBuffer = realloc(convBuffer,datalen); convBuffer = realloc(convBuffer,datalen);

View File

@ -153,7 +153,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
int dataBitLen; int dataBitLen;
assert(outFormat->bits==16); assert(outFormat->bits==16);
assert(outFormat->channels==2); assert(outFormat->channels==2 || outFormat->channels==1);
/* converts */ /* converts */
switch(inFormat->bits) { 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 */ /* converts only between 16 bit audio between mono and stereo */
switch(inFormat->channels) { if(inFormat->channels == outFormat->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:
dataChannelConv = dataBitConv; dataChannelConv = dataBitConv;
dataChannelLen = dataBitLen; dataChannelLen = dataBitLen;
break; }
default: else {
ERROR("only 1 or 2 channels are supported for conversion!\n"); switch(inFormat->channels) {
exit(EXIT_FAILURE); /* 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) { if(inFormat->sampleRate == outFormat->sampleRate) {
@ -247,7 +270,7 @@ void pcm_convertAudioFormat(AudioFormat * inFormat, char * inBuffer, size_t
} }
size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat, size_t pcm_sizeOfOutputBufferForAudioFormatConversion(AudioFormat * inFormat,
char * inBuffer, size_t inSize, AudioFormat * outFormat) size_t inSize, AudioFormat * outFormat)
{ {
const int shift = sizeof(mpd_sint16); const int shift = sizeof(mpd_sint16);
size_t outSize = inSize; size_t outSize = inSize;

View File

@ -37,6 +37,6 @@ 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,
char * inBuffer, size_t inSize, AudioFormat * outFormat); size_t inSize, AudioFormat * outFormat);
#endif #endif
/* vim:set shiftwidth=8 tabstop=8 expandtab: */ /* vim:set shiftwidth=8 tabstop=8 expandtab: */