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;
void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
if(!src) return;
dest->sampleRate = src->sampleRate;
dest->bits = src->bits;
dest->channels = src->channels;
memcpy(dest, src, sizeof(AudioFormat));
}
int cmpAudioFormat(AudioFormat * f1, AudioFormat * f2) {
return memcmp(f1, f2, sizeof(AudioFormat));
}
static AudioOutput ** audioOutputArray = NULL;
......@@ -179,7 +181,7 @@ void finishAudioDriver() {
int isCurrentAudioFormat(AudioFormat * audioFormat) {
if(!audioFormat) return 1;
if(memcmp(audioFormat,&audio_format,sizeof(AudioFormat)) != 0) return 0;
if(cmpAudioFormat(audioFormat, &audio_format) != 0) return 0;
return 1;
}
......
......@@ -36,6 +36,8 @@ typedef struct _AudioFormat {
void copyAudioFormat(AudioFormat * dest, AudioFormat * src);
int cmpAudioFormat(AudioFormat * dest, AudioFormat * src);
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
int parseAudioConfig(AudioFormat * audioFormat, char * conf);
......
......@@ -2,11 +2,13 @@
#include "list.h"
#include "log.h"
#include "pcm_utils.h"
#include <string.h>
#define AUDIO_OUTPUT_TYPE "type"
#define AUDIO_OUTPUT_NAME "name"
#define AUDIO_OUTPUT_FORMAT "format"
static List * audioOutputPluginList;
......@@ -29,26 +31,27 @@ void finishAudioOutputPlugins() {
freeList(audioOutputPluginList);
}
#define getBlockParam(name, str) { \
BlockParam * bp; \
#define getBlockParam(name, str, force) { \
bp = getBlockParam(param, name); \
if(bp == NULL) { \
if(force && bp == NULL) { \
ERROR("couldn't find parameter \"%s\" in audio output " \
"definition begining at %i\n", \
name, param->line); \
exit(EXIT_FAILURE); \
} \
str = bp->value; \
if(bp) str = bp->value; \
}
AudioOutput * newAudioOutput(ConfigParam * param) {
AudioOutput * ret = NULL;
void * data = NULL;
char * name = NULL;
char * format = NULL;
char * type = NULL;
BlockParam * bp;
getBlockParam(AUDIO_OUTPUT_NAME, name);
getBlockParam(AUDIO_OUTPUT_TYPE, type);
getBlockParam(AUDIO_OUTPUT_NAME, name, 1);
getBlockParam(AUDIO_OUTPUT_TYPE, type, 1);
if(findInList(audioOutputPluginList, type, &data)) {
AudioOutputPlugin * plugin = (AudioOutputPlugin *) data;
......@@ -62,6 +65,27 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
ret->sendMetdataFunc = plugin->sendMetdataFunc;
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) {
free(ret);
ret = NULL;
......@@ -77,12 +101,62 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
}
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);
}
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) {
if(!audioOutput->open) return -1;
if(!audioOutput->sameInAndOutFormats) {
convertAudioFormat(audioOutput, &playChunk, &size);
}
return audioOutput->playFunc(audioOutput, playChunk, size);
}
......@@ -93,6 +167,7 @@ void closeAudioOutput(AudioOutput * audioOutput) {
void finishAudioOutput(AudioOutput * audioOutput) {
closeAudioOutput(audioOutput);
audioOutput->finishDriverFunc(audioOutput);
if(audioOutput->convBuffer) free(audioOutput->convBuffer);
free(audioOutput->type);
free(audioOutput->name);
free(audioOutput);
......
......@@ -55,6 +55,13 @@ struct _AudioOutput {
AudioOutputCloseDeviceFunc closeDeviceFunc;
AudioOutputSendMetadataFunc sendMetdataFunc;
int convertAudioFormat;
AudioFormat inAudioFormat;
AudioFormat outAudioFormat;
char * convBuffer;
int convBufferLen;
int sameInAndOutFormats;
void * data;
};
......
......@@ -59,13 +59,6 @@ typedef struct _ShoutData {
float quality;
int bitrate;
AudioFormat outAudioFormat;
AudioFormat inAudioFormat;
char * convBuffer;
size_t convBufferLen;
/* shoud we convert the audio to a different format? */
int audioFormatConvert;
int opened;
......@@ -74,14 +67,15 @@ typedef struct _ShoutData {
int connAttempts;
time_t lastAttempt;
/* just a pointer to audioOutput->outAudioFormat */
AudioFormat * audioFormat;
} ShoutData;
static ShoutData * newShoutData() {
ShoutData * ret = malloc(sizeof(ShoutData));
ret->shoutConn = shout_new();
ret->convBuffer = NULL;
ret->convBufferLen = 0;
ret->opened = 0;
ret->tag = NULL;
ret->tagToSend = 0;
......@@ -89,6 +83,7 @@ static ShoutData * newShoutData() {
ret->quality = -1.0;
ret->connAttempts = 0;
ret->lastAttempt = 0;
ret->audioFormat = NULL;
return ret;
}
......@@ -96,7 +91,6 @@ static ShoutData * newShoutData() {
static void freeShoutData(ShoutData * sd) {
if(sd->shoutConn) shout_free(sd->shoutConn);
if(sd->tag) freeMpdTag(sd->tag);
if(sd->convBuffer) free(sd->convBuffer);
free(sd);
}
......@@ -194,11 +188,7 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
}
checkBlockParam("format");
if(0 != parseAudioConfig(&(sd->outAudioFormat), blockParam->value)) {
ERROR("error parsing format at line %i\n", blockParam->line);
exit(EXIT_FAILURE);
}
sd->audioFormat = &audioOutput->outAudioFormat;
if(shout_set_host(sd->shoutConn, host) != SHOUTERR_SUCCESS ||
shout_set_port(sd->shoutConn, port) != SHOUTERR_SUCCESS ||
......@@ -222,11 +212,11 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
char temp[11];
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);
snprintf(temp, sizeof(temp), "%d",
sd->outAudioFormat.sampleRate);
snprintf(temp, sizeof(temp), "%d", sd->audioFormat->sampleRate);
shout_set_audio_info(sd->shoutConn, SHOUT_AI_SAMPLERATE, temp);
if(sd->quality >= 0) {
......@@ -352,8 +342,8 @@ static int initEncoder(ShoutData * sd) {
if(sd->quality >= 0) {
if( 0 != vorbis_encode_init_vbr(&(sd->vi),
sd->outAudioFormat.channels,
sd->outAudioFormat.sampleRate, sd->quality*0.1) )
sd->audioFormat->channels,
sd->audioFormat->sampleRate, sd->quality*0.1) )
{
ERROR("problem seting up vorbis encoder for shout\n");
vorbis_info_clear(&(sd->vi));
......@@ -362,8 +352,8 @@ static int initEncoder(ShoutData * sd) {
}
else {
if( 0 != vorbis_encode_init(&(sd->vi),
sd->outAudioFormat.channels,
sd->outAudioFormat.sampleRate, -1.0,
sd->audioFormat->channels,
sd->audioFormat->sampleRate, -1.0,
sd->bitrate*1000, -1.0) )
{
ERROR("problem seting up vorbis encoder for shout\n");
......@@ -439,15 +429,6 @@ static int myShout_openDevice(AudioOutput * audioOutput,
{
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;
if(sd->opened) return 0;
......@@ -460,25 +441,6 @@ static int myShout_openDevice(AudioOutput * audioOutput,
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) {
ogg_int64_t granulepos = sd->vd.granulepos;
......@@ -516,7 +478,7 @@ static int myShout_play(AudioOutput * audioOutput, char * playChunk, int size) {
ShoutData * sd = (ShoutData *)audioOutput->data;
float ** vorbbuf;
int samples;
int bytes = sd->outAudioFormat.bits/8;
int bytes = sd->audioFormat->bits/8;
if(sd->opened && sd->tagToSend) myShout_sendMetadata(sd);
......@@ -526,18 +488,14 @@ static int myShout_play(AudioOutput * audioOutput, char * playChunk, int size) {
}
}
if(sd->audioFormatConvert) {
myShout_convertAudioFormat(sd, &playChunk, &size);
}
samples = size/(bytes*sd->outAudioFormat.channels);
samples = size/(bytes*sd->audioFormat->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++) {
for(j=0; j<sd->audioFormat->channels; j++) {
vorbbuf[j][i] = (*((mpd_sint16 *)playChunk)) / 32768.0;
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