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:
parent
413bf61ea1
commit
12597322a2
48
src/audio.c
48
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);
|
||||
}
|
||||
|
||||
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!=':') {
|
||||
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() {
|
||||
|
@ -35,6 +35,8 @@ typedef struct _AudioFormat {
|
||||
|
||||
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
|
||||
|
||||
int parseAudioConfig(AudioFormat * audioFormat, char * conf);
|
||||
|
||||
void initAudioConfig();
|
||||
|
||||
void finishAudioConfig();
|
||||
|
@ -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;
|
||||
|
||||
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++) {
|
||||
vorbbuf[0][j] = (*((mpd_sint16 *)(playChunk+i))) / 32768.0;
|
||||
vorbbuf[1][j] = (*((mpd_sint16 *)(playChunk+i+2))) / 32768.0;
|
||||
samples = size/(bytes*sd->outAudioFormat.channels);
|
||||
|
||||
/* 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);
|
||||
|
@ -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] = {
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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: */
|
||||
|
Loading…
Reference in New Issue
Block a user