Commit ee5d5d63 authored by Warren Dukes's avatar Warren Dukes

abstract out audioFormat conversion from shout plugin to the audioOutput layer,

now format can be specified for each different audioOutput device git-svn-id: https://svn.musicpd.org/mpd/trunk@2474 09075e82-0dd4-0310-85a5-a0d7c8717e4f
parent 02982397
...@@ -34,9 +34,11 @@ static AudioFormat * audio_configFormat = NULL; ...@@ -34,9 +34,11 @@ static AudioFormat * audio_configFormat = NULL;
void copyAudioFormat(AudioFormat * dest, AudioFormat * src) { void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
if(!src) return; if(!src) return;
dest->sampleRate = src->sampleRate; memcpy(dest, src, sizeof(AudioFormat));
dest->bits = src->bits; }
dest->channels = src->channels;
int cmpAudioFormat(AudioFormat * f1, AudioFormat * f2) {
return memcmp(f1, f2, sizeof(AudioFormat));
} }
static AudioOutput ** audioOutputArray = NULL; static AudioOutput ** audioOutputArray = NULL;
...@@ -179,7 +181,7 @@ void finishAudioDriver() { ...@@ -179,7 +181,7 @@ void finishAudioDriver() {
int isCurrentAudioFormat(AudioFormat * audioFormat) { int isCurrentAudioFormat(AudioFormat * audioFormat) {
if(!audioFormat) return 1; if(!audioFormat) return 1;
if(memcmp(audioFormat,&audio_format,sizeof(AudioFormat)) != 0) return 0; if(cmpAudioFormat(audioFormat, &audio_format) != 0) return 0;
return 1; return 1;
} }
......
...@@ -36,6 +36,8 @@ typedef struct _AudioFormat { ...@@ -36,6 +36,8 @@ typedef struct _AudioFormat {
void copyAudioFormat(AudioFormat * dest, AudioFormat * src); void copyAudioFormat(AudioFormat * dest, AudioFormat * src);
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);
......
...@@ -2,11 +2,13 @@ ...@@ -2,11 +2,13 @@
#include "list.h" #include "list.h"
#include "log.h" #include "log.h"
#include "pcm_utils.h"
#include <string.h> #include <string.h>
#define AUDIO_OUTPUT_TYPE "type" #define AUDIO_OUTPUT_TYPE "type"
#define AUDIO_OUTPUT_NAME "name" #define AUDIO_OUTPUT_NAME "name"
#define AUDIO_OUTPUT_FORMAT "format"
static List * audioOutputPluginList; static List * audioOutputPluginList;
...@@ -29,26 +31,27 @@ void finishAudioOutputPlugins() { ...@@ -29,26 +31,27 @@ void finishAudioOutputPlugins() {
freeList(audioOutputPluginList); freeList(audioOutputPluginList);
} }
#define getBlockParam(name, str) { \ #define getBlockParam(name, str, force) { \
BlockParam * bp; \
bp = getBlockParam(param, name); \ bp = getBlockParam(param, name); \
if(bp == NULL) { \ if(force && bp == NULL) { \
ERROR("couldn't find parameter \"%s\" in audio output " \ ERROR("couldn't find parameter \"%s\" in audio output " \
"definition begining at %i\n", \ "definition begining at %i\n", \
name, param->line); \ name, param->line); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
str = bp->value; \ if(bp) str = bp->value; \
} }
AudioOutput * newAudioOutput(ConfigParam * param) { AudioOutput * newAudioOutput(ConfigParam * param) {
AudioOutput * ret = NULL; AudioOutput * ret = NULL;
void * data = NULL; void * data = NULL;
char * name = NULL; char * name = NULL;
char * format = NULL;
char * type = NULL; char * type = NULL;
BlockParam * bp;
getBlockParam(AUDIO_OUTPUT_NAME, name); getBlockParam(AUDIO_OUTPUT_NAME, name, 1);
getBlockParam(AUDIO_OUTPUT_TYPE, type); getBlockParam(AUDIO_OUTPUT_TYPE, type, 1);
if(findInList(audioOutputPluginList, type, &data)) { if(findInList(audioOutputPluginList, type, &data)) {
AudioOutputPlugin * plugin = (AudioOutputPlugin *) data; AudioOutputPlugin * plugin = (AudioOutputPlugin *) data;
...@@ -62,6 +65,27 @@ AudioOutput * newAudioOutput(ConfigParam * param) { ...@@ -62,6 +65,27 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
ret->sendMetdataFunc = plugin->sendMetdataFunc; ret->sendMetdataFunc = plugin->sendMetdataFunc;
ret->open = 0; ret->open = 0;
ret->convertAudioFormat = 0;
ret->sameInAndOutFormats = 0;
ret->convBuffer = NULL;
ret->convBufferLen = 0;
memset(&ret->inAudioFormat, 0, sizeof(AudioFormat));
memset(&ret->outAudioFormat, 0, sizeof(AudioFormat));
getBlockParam(AUDIO_OUTPUT_FORMAT, format, 0);
if(format) {
ret->convertAudioFormat = 1;
if(0 != parseAudioConfig(&ret->outAudioFormat, format))
{
ERROR("error parsing format at line %i\n",
bp->line);
exit(EXIT_FAILURE);
}
}
if(plugin->initDriverFunc(ret, param) != 0) { if(plugin->initDriverFunc(ret, param) != 0) {
free(ret); free(ret);
ret = NULL; ret = NULL;
...@@ -77,12 +101,62 @@ AudioOutput * newAudioOutput(ConfigParam * param) { ...@@ -77,12 +101,62 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
} }
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat) { int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat) {
if(audioOutput->open) closeAudioOutput(audioOutput); if(audioOutput->open) {
if(cmpAudioFormat(audioFormat, &audioOutput->inAudioFormat)
== 0)
{
return 0;
}
closeAudioOutput(audioOutput);
}
copyAudioFormat(&audioOutput->inAudioFormat, audioFormat);
if(audioOutput->convertAudioFormat) {
if(cmpAudioFormat(&audioOutput->inAudioFormat,
&audioOutput->outAudioFormat) == 0)
{
audioOutput->sameInAndOutFormats = 1;
}
else audioOutput->sameInAndOutFormats = 0;
}
else {
audioOutput->sameInAndOutFormats = 1;
copyAudioFormat(&audioOutput->outAudioFormat,
&audioOutput->inAudioFormat);
}
return audioOutput->openDeviceFunc(audioOutput, audioFormat); return audioOutput->openDeviceFunc(audioOutput, audioFormat);
} }
static void convertAudioFormat(AudioOutput * audioOutput, char ** chunkArgPtr,
int * sizeArgPtr)
{
int size = pcm_sizeOfOutputBufferForAudioFormatConversion(
&(audioOutput->inAudioFormat), *sizeArgPtr,
&(audioOutput->outAudioFormat));
if(size > audioOutput->convBufferLen) {
audioOutput->convBuffer =
realloc(audioOutput->convBuffer, size);
audioOutput->convBufferLen = size;
}
pcm_convertAudioFormat(&(audioOutput->inAudioFormat), *chunkArgPtr,
*sizeArgPtr, &(audioOutput->outAudioFormat),
audioOutput->convBuffer);
*sizeArgPtr = size;
*chunkArgPtr = audioOutput->convBuffer;
}
int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size) { int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size) {
if(!audioOutput->open) return -1; if(!audioOutput->open) return -1;
if(!audioOutput->sameInAndOutFormats) {
convertAudioFormat(audioOutput, &playChunk, &size);
}
return audioOutput->playFunc(audioOutput, playChunk, size); return audioOutput->playFunc(audioOutput, playChunk, size);
} }
...@@ -93,6 +167,7 @@ void closeAudioOutput(AudioOutput * audioOutput) { ...@@ -93,6 +167,7 @@ void closeAudioOutput(AudioOutput * 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);
free(audioOutput->type); free(audioOutput->type);
free(audioOutput->name); free(audioOutput->name);
free(audioOutput); free(audioOutput);
......
...@@ -55,6 +55,13 @@ struct _AudioOutput { ...@@ -55,6 +55,13 @@ struct _AudioOutput {
AudioOutputCloseDeviceFunc closeDeviceFunc; AudioOutputCloseDeviceFunc closeDeviceFunc;
AudioOutputSendMetadataFunc sendMetdataFunc; AudioOutputSendMetadataFunc sendMetdataFunc;
int convertAudioFormat;
AudioFormat inAudioFormat;
AudioFormat outAudioFormat;
char * convBuffer;
int convBufferLen;
int sameInAndOutFormats;
void * data; void * data;
}; };
......
...@@ -59,13 +59,6 @@ typedef struct _ShoutData { ...@@ -59,13 +59,6 @@ typedef struct _ShoutData {
float quality; float quality;
int bitrate; int bitrate;
AudioFormat outAudioFormat;
AudioFormat inAudioFormat;
char * convBuffer;
size_t convBufferLen;
/* shoud we convert the audio to a different format? */
int audioFormatConvert;
int opened; int opened;
...@@ -74,14 +67,15 @@ typedef struct _ShoutData { ...@@ -74,14 +67,15 @@ typedef struct _ShoutData {
int connAttempts; int connAttempts;
time_t lastAttempt; time_t lastAttempt;
/* just a pointer to audioOutput->outAudioFormat */
AudioFormat * audioFormat;
} ShoutData; } ShoutData;
static ShoutData * newShoutData() { static ShoutData * newShoutData() {
ShoutData * ret = malloc(sizeof(ShoutData)); ShoutData * ret = malloc(sizeof(ShoutData));
ret->shoutConn = shout_new(); ret->shoutConn = shout_new();
ret->convBuffer = NULL;
ret->convBufferLen = 0;
ret->opened = 0; ret->opened = 0;
ret->tag = NULL; ret->tag = NULL;
ret->tagToSend = 0; ret->tagToSend = 0;
...@@ -89,6 +83,7 @@ static ShoutData * newShoutData() { ...@@ -89,6 +83,7 @@ static ShoutData * newShoutData() {
ret->quality = -1.0; ret->quality = -1.0;
ret->connAttempts = 0; ret->connAttempts = 0;
ret->lastAttempt = 0; ret->lastAttempt = 0;
ret->audioFormat = NULL;
return ret; return ret;
} }
...@@ -96,7 +91,6 @@ static ShoutData * newShoutData() { ...@@ -96,7 +91,6 @@ static ShoutData * newShoutData() {
static void freeShoutData(ShoutData * sd) { static void freeShoutData(ShoutData * sd) {
if(sd->shoutConn) shout_free(sd->shoutConn); if(sd->shoutConn) shout_free(sd->shoutConn);
if(sd->tag) freeMpdTag(sd->tag); if(sd->tag) freeMpdTag(sd->tag);
if(sd->convBuffer) free(sd->convBuffer);
free(sd); free(sd);
} }
...@@ -194,11 +188,7 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) { ...@@ -194,11 +188,7 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
} }
checkBlockParam("format"); checkBlockParam("format");
sd->audioFormat = &audioOutput->outAudioFormat;
if(0 != parseAudioConfig(&(sd->outAudioFormat), blockParam->value)) {
ERROR("error parsing format at line %i\n", blockParam->line);
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 ||
...@@ -222,11 +212,11 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) { ...@@ -222,11 +212,11 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
char temp[11]; char temp[11];
memset(temp, 0, sizeof(temp)); memset(temp, 0, sizeof(temp));
snprintf(temp, sizeof(temp), "%d", sd->outAudioFormat.channels); snprintf(temp, sizeof(temp), "%d", sd->audioFormat->channels);
shout_set_audio_info(sd->shoutConn, SHOUT_AI_CHANNELS, temp); shout_set_audio_info(sd->shoutConn, SHOUT_AI_CHANNELS, temp);
snprintf(temp, sizeof(temp), "%d", snprintf(temp, sizeof(temp), "%d", sd->audioFormat->sampleRate);
sd->outAudioFormat.sampleRate);
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) {
...@@ -352,8 +342,8 @@ static int initEncoder(ShoutData * sd) { ...@@ -352,8 +342,8 @@ static int initEncoder(ShoutData * sd) {
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->outAudioFormat.channels, sd->audioFormat->channels,
sd->outAudioFormat.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));
...@@ -362,8 +352,8 @@ static int initEncoder(ShoutData * sd) { ...@@ -362,8 +352,8 @@ static int initEncoder(ShoutData * sd) {
} }
else { else {
if( 0 != vorbis_encode_init(&(sd->vi), if( 0 != vorbis_encode_init(&(sd->vi),
sd->outAudioFormat.channels, sd->audioFormat->channels,
sd->outAudioFormat.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");
...@@ -439,15 +429,6 @@ static int myShout_openDevice(AudioOutput * audioOutput, ...@@ -439,15 +429,6 @@ static int myShout_openDevice(AudioOutput * audioOutput,
{ {
ShoutData * sd = (ShoutData *)audioOutput->data; ShoutData * sd = (ShoutData *)audioOutput->data;
memcpy(&(sd->inAudioFormat), audioFormat, sizeof(AudioFormat));
if(0 == memcmp(&(sd->inAudioFormat), &(sd->outAudioFormat),
sizeof(AudioFormat)))
{
sd->audioFormatConvert = 0;
}
else sd->audioFormatConvert = 1;
audioOutput->open = 1; audioOutput->open = 1;
if(sd->opened) return 0; if(sd->opened) return 0;
...@@ -460,25 +441,6 @@ static int myShout_openDevice(AudioOutput * audioOutput, ...@@ -460,25 +441,6 @@ static int myShout_openDevice(AudioOutput * audioOutput,
return 0; return 0;
} }
static void myShout_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 void myShout_sendMetadata(ShoutData * sd) { static void myShout_sendMetadata(ShoutData * sd) {
ogg_int64_t granulepos = sd->vd.granulepos; ogg_int64_t granulepos = sd->vd.granulepos;
...@@ -516,7 +478,7 @@ static int myShout_play(AudioOutput * audioOutput, char * playChunk, int size) { ...@@ -516,7 +478,7 @@ static int myShout_play(AudioOutput * audioOutput, char * playChunk, int size) {
ShoutData * sd = (ShoutData *)audioOutput->data; ShoutData * sd = (ShoutData *)audioOutput->data;
float ** vorbbuf; float ** vorbbuf;
int samples; int samples;
int bytes = sd->outAudioFormat.bits/8; int bytes = sd->audioFormat->bits/8;
if(sd->opened && sd->tagToSend) myShout_sendMetadata(sd); if(sd->opened && sd->tagToSend) myShout_sendMetadata(sd);
...@@ -526,18 +488,14 @@ static int myShout_play(AudioOutput * audioOutput, char * playChunk, int size) { ...@@ -526,18 +488,14 @@ static int myShout_play(AudioOutput * audioOutput, char * playChunk, int size) {
} }
} }
if(sd->audioFormatConvert) { samples = size/(bytes*sd->audioFormat->channels);
myShout_convertAudioFormat(sd, &playChunk, &size);
}
samples = size/(bytes*sd->outAudioFormat.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->outAudioFormat.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;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment