audio.c 5.87 KB
Newer Older
Warren Dukes's avatar
Warren Dukes committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* the Music Player Daemon (MPD)
 * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
 * This project's homepage is: http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "audio.h"
20
#include "audioOutput.h"
Warren Dukes's avatar
Warren Dukes committed
21 22 23 24
#include "conf.h"
#include "log.h"
#include "sig_handlers.h"

25
#include <stdlib.h>
Warren Dukes's avatar
Warren Dukes committed
26 27 28 29
#include <string.h>
#include <assert.h>
#include <signal.h>

30
static AudioFormat audio_format;
Warren Dukes's avatar
Warren Dukes committed
31

32 33
static AudioFormat * audio_configFormat = NULL;

34
void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
Warren Dukes's avatar
Warren Dukes committed
35 36
	if(!src) return;

37 38 39 40 41
        dest->sampleRate = src->sampleRate;
        dest->bits = src->bits;
        dest->channels = src->channels;
}

42 43 44
static AudioOutput ** audioOutputArray = NULL;
static int audioOutputArraySize = 0;

45
extern AudioOutputPlugin aoPlugin;
46
extern AudioOutputPlugin shoutPlugin;
Warren Dukes's avatar
Warren Dukes committed
47

48
void initAudioDriver() {
49 50 51
	ConfigParam * param = NULL;
	int i;

52 53
	initAudioOutputPlugins();
	loadAudioOutputPlugin(&aoPlugin);
54
	loadAudioOutputPlugin(&shoutPlugin);
Warren Dukes's avatar
Warren Dukes committed
55

56 57 58 59 60 61 62 63 64 65 66 67 68 69
	while((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param))) {
		i = audioOutputArraySize++;

		audioOutputArray = realloc(audioOutputArray,
				audioOutputArraySize*sizeof(AudioOutput *));
	
		audioOutputArray[i] = newAudioOutput(param);

		if(!audioOutputArray[i]) {
			ERROR("problems configuring output device defined at "
					"line %i\n", param->line);
			exit(EXIT_FAILURE);
		}
	}
Warren Dukes's avatar
Warren Dukes committed
70 71
}

72 73 74 75 76 77 78 79 80 81
void getOutputAudioFormat(AudioFormat * inAudioFormat, 
                AudioFormat * outAudioFormat)
{
        if(audio_configFormat) {
                copyAudioFormat(outAudioFormat,audio_configFormat);
        }
        else copyAudioFormat(outAudioFormat,inAudioFormat);
}

void initAudioConfig() {
82
        ConfigParam * param = getConfigParam(CONF_AUDIO_OUTPUT_FORMAT);
83

84
        if(NULL == param || NULL == param->value) return;
85 86 87

        audio_configFormat = malloc(sizeof(AudioFormat));

88 89 90 91 92
	if(0 != parseAudioConfig(audio_configFormat, param->value)) {
		ERROR("error parsing \"%s\" at line %i\n", 
				CONF_AUDIO_OUTPUT_FORMAT, param->line);
		exit(EXIT_FAILURE);
	}
93 94 95 96 97 98
}

int parseAudioConfig(AudioFormat * audioFormat, char * conf) {
        char * test;

        memset(audioFormat,0,sizeof(AudioFormat));
99

100
        audioFormat->sampleRate = strtol(conf,&test,10);
101 102 103
       
        if(*test!=':') {
                ERROR("error parsing audio output format: %s\n",conf);
104
		return -1;
105 106
        }
 
107
        /*switch(audioFormat->sampleRate) {
108 109
        case 48000:
        case 44100:
110 111
        case 32000:
        case 16000:
112 113 114
                break;
        default:
                ERROR("sample rate %i can not be used for audio output\n",
115 116
                        (int)audioFormat->sampleRate);
		return -1
Warren Dukes's avatar
Warren Dukes committed
117 118
        }*/

119
        if(audioFormat->sampleRate <= 0) {
Warren Dukes's avatar
Warren Dukes committed
120
                ERROR("sample rate %i is not >= 0\n",
121 122
                                (int)audioFormat->sampleRate);
		return -1;
123 124
        }

125
        audioFormat->bits = strtol(test+1,&test,10);
126 127 128
        
        if(*test!=':') {
                ERROR("error parsing audio output format: %s\n",conf);
129
		return -1;
130 131
        }

132
        switch(audioFormat->bits) {
133 134 135 136
        case 16:
                break;
        default:
                ERROR("bits %i can not be used for audio output\n",
137 138
                        (int)audioFormat->bits);
		return -1;
139 140
        }

141
        audioFormat->channels = strtol(test+1,&test,10);
142 143 144
        
        if(*test!='\0') {
                ERROR("error parsing audio output format: %s\n",conf);
145
		return -1;
146 147
        }

148 149
        switch(audioFormat->channels) {
	case 1:
150 151 152 153
        case 2:
                break;
        default:
                ERROR("channels %i can not be used for audio output\n",
154 155
                        (int)audioFormat->channels);
		return -1;
156
        }
157 158

	return 0;
159 160 161 162 163 164
}

void finishAudioConfig() {
        if(audio_configFormat) free(audio_configFormat);
}

Warren Dukes's avatar
Warren Dukes committed
165
void finishAudioDriver() {
166 167 168 169 170 171 172 173 174
	int i;

	for(i = 0; i < audioOutputArraySize; i++) {
		finishAudioOutput(audioOutputArray[i]);
	}

	free(audioOutputArray);
	audioOutputArray = NULL;
	audioOutputArraySize = 0;
Warren Dukes's avatar
Warren Dukes committed
175 176 177
}

int isCurrentAudioFormat(AudioFormat * audioFormat) {
178
	if(!audioFormat) return 1;
Warren Dukes's avatar
Warren Dukes committed
179

180
	if(memcmp(audioFormat,&audio_format,sizeof(AudioFormat)) != 0) return 0;
Warren Dukes's avatar
Warren Dukes committed
181

Warren Dukes's avatar
Warren Dukes committed
182 183 184
	return 1;
}

185
int openAudioDevice(AudioFormat * audioFormat) {
186 187 188 189 190 191 192 193
	int isCurrentFormat = isCurrentAudioFormat(audioFormat);
	int ret = -1;
	int i;

	if(!audioOutputArray) return -1;

	if(!isCurrentFormat) {
		copyAudioFormat(&audio_format, audioFormat);
Warren Dukes's avatar
Warren Dukes committed
194 195
	}

196 197
	for(i = 0; i < audioOutputArraySize; i++) {
		if(!audioOutputArray[i]->open || !isCurrentFormat) {
198
			openAudioOutput(audioOutputArray[i], &audio_format);
199
		}
200
		if(audioOutputArray[i]->open) ret = 0;
201 202 203
	}

	return ret;
204
}
Warren Dukes's avatar
Warren Dukes committed
205

Warren Dukes's avatar
Warren Dukes committed
206
int playAudio(char * playChunk, int size) {
207 208 209 210 211 212 213 214 215 216
	int ret = -1;
	int i;

	for(i = 0; i < audioOutputArraySize; i++) {
		if(0 == playAudioOutput(audioOutputArray[i], playChunk, size)) {
			ret = 0;
		}
	}

	return ret;
Warren Dukes's avatar
Warren Dukes committed
217 218
}

219
int isAudioDeviceOpen() {
220 221 222 223 224 225 226 227
	int ret = 0;
	int i;

	for(i = 0; i < audioOutputArraySize; i++) {
		ret |= audioOutputArray[i]->open;
	}

	return ret;
228 229
}

230
void closeAudioDevice() {
231 232 233 234 235
	int i;

	for(i = 0; i < audioOutputArraySize; i++) {
		closeAudioOutput(audioOutputArray[i]);
	}
Warren Dukes's avatar
Warren Dukes committed
236
}
237

238
void sendMetadataToAudioDevice(MpdTag * tag) {
239 240 241 242 243
	int i;

	for(i = 0; i < audioOutputArraySize; i++) {
		sendMetadataToAudioOutput(audioOutputArray[i], tag);
	}
244
}