Initial revision 6759
[qball-mpd.git] / src / .svn / text-base / audio.c.svn-base
blob96712d713ea341328c218ae79fdbbd7551f50a5d
1 /* the Music Player Daemon (MPD)
2  * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3  * This project's homepage is: http://www.musicpd.org
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
19 #include "audio.h"
20 #include "audioOutput.h"
21 #include "conf.h"
22 #include "log.h"
23 #include "sig_handlers.h"
24 #include "command.h"
25 #include "playerData.h"
26 #include "utils.h"
27 #include "state_file.h"
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <signal.h>
33 #include <sys/stat.h>
34 #include <sys/param.h>
35 #include <errno.h>
36 #include <unistd.h>
38 #define AUDIO_DEVICE_STATE      "audio_device_state:"
39 #define AUDIO_DEVICE_STATE_LEN  19      /* strlen(AUDIO_DEVICE_STATE) */
40 #define AUDIO_BUFFER_SIZE       2*MAXPATHLEN
42 static AudioFormat audio_format;
44 static AudioFormat *audio_configFormat;
46 static AudioOutput *audioOutputArray;
47 static mpd_uint8 audioOutputArraySize;
49 #define DEVICE_OFF        0x00
50 #define DEVICE_ENABLE     0x01   /* currently off, but to be turned on */
51 #define DEVICE_ON         0x03
52 #define DEVICE_DISABLE    0x04   /* currently on, but to be turned off */
54 /* the audioEnabledArray should be stuck into shared memory, and then disable
55    and enable in playAudio() routine */
56 static mpd_uint8 *audioDeviceStates;
58 static mpd_uint8 audioOpened;
60 static mpd_sint32 audioBufferSize;
61 static char *audioBuffer;
62 static mpd_sint32 audioBufferPos;
64 size_t audio_device_count(void)
66         size_t nr = 0;
67         ConfigParam *param = NULL;
69         while ((param = getNextConfigParam(CONF_AUDIO_OUTPUT, param)))
70                 nr++;
71         if (!nr)
72                 nr = 1; /* we'll always have at least one device  */
73         return nr;
76 void copyAudioFormat(AudioFormat * dest, AudioFormat * src)
78         if (!src)
79                 return;
81         memcpy(dest, src, sizeof(AudioFormat));
84 int cmpAudioFormat(AudioFormat * f1, AudioFormat * f2)
86         if (f1 && f2 && (f1->sampleRate == f2->sampleRate) &&
87             (f1->bits == f2->bits) && (f1->channels == f2->channels))
88                 return 0;
89         return 1;
92 void loadAudioDrivers(void)
94         initAudioOutputPlugins();
95         loadAudioOutputPlugin(&shoutPlugin);
96         loadAudioOutputPlugin(&nullPlugin);
97         loadAudioOutputPlugin(&fifoPlugin);
98         loadAudioOutputPlugin(&alsaPlugin);
99         loadAudioOutputPlugin(&aoPlugin);
100         loadAudioOutputPlugin(&ossPlugin);
101         loadAudioOutputPlugin(&osxPlugin);
102         loadAudioOutputPlugin(&pulsePlugin);
103         loadAudioOutputPlugin(&mvpPlugin);
104         loadAudioOutputPlugin(&jackPlugin);
107 /* make sure initPlayerData is called before this function!! */
108 void initAudioDriver(void)
110         ConfigParam *param = NULL;
111         int i;
113         loadAudioDrivers();
115         audioOutputArraySize = audio_device_count();
116         audioDeviceStates = (getPlayerData())->audioDeviceStates;
117         audioOutputArray = xmalloc(sizeof(AudioOutput) * audioOutputArraySize);
119         for (i = 0; i < audioOutputArraySize; i++)
120         {
121                 AudioOutput *output = &audioOutputArray[i];
122                 int j;
124                 param = getNextConfigParam(CONF_AUDIO_OUTPUT, param);
126                 /* only allow param to be NULL if there just one audioOutput */
127                 assert(param || (audioOutputArraySize == 1));
129                 if (!initAudioOutput(output, param)) {
130                         if (param)
131                         {
132                                 FATAL("problems configuring output device "
133                                       "defined at line %i\n", param->line);
134                         }
135                         else
136                         {
137                                 FATAL("No audio_output specified and unable to "
138                                       "detect a default audio output device\n");
139                         }
140                 }
142                 /* require output names to be unique: */
143                 for (j = 0; j < i; j++) {
144                         if (!strcmp(output->name, audioOutputArray[j].name)) {
145                                 FATAL("output devices with identical "
146                                       "names: %s\n", output->name);
147                         }
148                 }
149                 audioDeviceStates[i] = DEVICE_ENABLE;
150         }
153 void getOutputAudioFormat(AudioFormat * inAudioFormat,
154                           AudioFormat * outAudioFormat)
156         if (audio_configFormat) {
157                 copyAudioFormat(outAudioFormat, audio_configFormat);
158         } else
159                 copyAudioFormat(outAudioFormat, inAudioFormat);
162 void initAudioConfig(void)
164         ConfigParam *param = getConfigParam(CONF_AUDIO_OUTPUT_FORMAT);
166         if (NULL == param || NULL == param->value)
167                 return;
169         audio_configFormat = xmalloc(sizeof(AudioFormat));
171         if (0 != parseAudioConfig(audio_configFormat, param->value)) {
172                 FATAL("error parsing \"%s\" at line %i\n",
173                       CONF_AUDIO_OUTPUT_FORMAT, param->line);
174         }
177 int parseAudioConfig(AudioFormat * audioFormat, char *conf)
179         char *test;
181         memset(audioFormat, 0, sizeof(AudioFormat));
183         audioFormat->sampleRate = strtol(conf, &test, 10);
185         if (*test != ':') {
186                 ERROR("error parsing audio output format: %s\n", conf);
187                 return -1;
188         }
190         /*switch(audioFormat->sampleRate) {
191            case 48000:
192            case 44100:
193            case 32000:
194            case 16000:
195            break;
196            default:
197            ERROR("sample rate %i can not be used for audio output\n",
198            (int)audioFormat->sampleRate);
199            return -1
200            } */
202         if (audioFormat->sampleRate <= 0) {
203                 ERROR("sample rate %i is not >= 0\n",
204                       (int)audioFormat->sampleRate);
205                 return -1;
206         }
208         audioFormat->bits = strtol(test + 1, &test, 10);
210         if (*test != ':') {
211                 ERROR("error parsing audio output format: %s\n", conf);
212                 return -1;
213         }
215         switch (audioFormat->bits) {
216         case 16:
217                 break;
218         default:
219                 ERROR("bits %i can not be used for audio output\n",
220                       (int)audioFormat->bits);
221                 return -1;
222         }
224         audioFormat->channels = strtol(test + 1, &test, 10);
226         if (*test != '\0') {
227                 ERROR("error parsing audio output format: %s\n", conf);
228                 return -1;
229         }
231         switch (audioFormat->channels) {
232         case 1:
233         case 2:
234                 break;
235         default:
236                 ERROR("channels %i can not be used for audio output\n",
237                       (int)audioFormat->channels);
238                 return -1;
239         }
241         return 0;
244 void finishAudioConfig(void)
246         if (audio_configFormat)
247                 free(audio_configFormat);
250 void finishAudioDriver(void)
252         int i;
254         for (i = 0; i < audioOutputArraySize; i++) {
255                 finishAudioOutput(&audioOutputArray[i]);
256         }
258         free(audioOutputArray);
259         audioOutputArray = NULL;
260         audioOutputArraySize = 0;
263 int isCurrentAudioFormat(AudioFormat * audioFormat)
265         if (!audioFormat)
266                 return 1;
268         if (cmpAudioFormat(audioFormat, &audio_format) != 0)
269                 return 0;
271         return 1;
274 static void syncAudioDeviceStates(void)
276         AudioOutput *audioOutput;
277         int i;
279         if (!audio_format.channels)
280                 return;
282         for (i = 0; i < audioOutputArraySize; ++i) {
283                 audioOutput = &audioOutputArray[i];
284                 switch (audioDeviceStates[i]) {
285                 case DEVICE_ON:
286                         /* This will reopen only if the audio format changed */
287                         if (openAudioOutput(audioOutput, &audio_format) < 0)
288                                 audioDeviceStates[i] = DEVICE_ENABLE;
289                         break;
290                 case DEVICE_ENABLE:
291                         if (openAudioOutput(audioOutput, &audio_format) == 0)
292                                 audioDeviceStates[i] = DEVICE_ON;
293                         break;
294                 case DEVICE_DISABLE:
295                         dropBufferedAudioOutput(audioOutput);
296                         closeAudioOutput(audioOutput);
297                         audioDeviceStates[i] = DEVICE_OFF;
298                         break;
299                 }
300         }
303 static int flushAudioBuffer(void)
305         int ret = -1;
306         int i, err;
308         if (audioBufferPos == 0)
309                 return 0;
311         syncAudioDeviceStates();
313         for (i = 0; i < audioOutputArraySize; ++i) {
314                 if (audioDeviceStates[i] != DEVICE_ON)
315                         continue;
316                 err = playAudioOutput(&audioOutputArray[i], audioBuffer,
317                                       audioBufferPos);
318                 if (!err)
319                         ret = 0;
320                 else if (err < 0)
321                         /* device should already be closed if the play
322                          * func returned an error */
323                         audioDeviceStates[i] = DEVICE_ENABLE;
324         }
326         audioBufferPos = 0;
328         return ret;
331 int openAudioDevice(AudioFormat * audioFormat)
333         int ret = -1;
334         int i;
336         if (!audioOutputArray)
337                 return -1;
339         if (!audioOpened || !isCurrentAudioFormat(audioFormat)) {
340                 flushAudioBuffer();
341                 copyAudioFormat(&audio_format, audioFormat);
342                 audioBufferSize = (audio_format.bits >> 3) *
343                     audio_format.channels;
344                 audioBufferSize *= audio_format.sampleRate >> 5;
345                 audioBuffer = xrealloc(audioBuffer, audioBufferSize);
346         }
348         syncAudioDeviceStates();
350         for (i = 0; i < audioOutputArraySize; ++i) {
351                 if (audioOutputArray[i].open)
352                         ret = 0;
353         }
355         if (ret == 0)
356                 audioOpened = 1;
357         else {
358                 /* close all devices if there was an error */
359                 for (i = 0; i < audioOutputArraySize; ++i) {
360                         closeAudioOutput(&audioOutputArray[i]);
361                 }
363                 audioOpened = 0;
364         }
366         return ret;
369 int playAudio(char *playChunk, int size)
371         int send;
373         while (size > 0) {
374                 send = audioBufferSize - audioBufferPos;
375                 send = send < size ? send : size;
377                 memcpy(audioBuffer + audioBufferPos, playChunk, send);
378                 audioBufferPos += send;
379                 size -= send;
380                 playChunk += send;
382                 if (audioBufferPos == audioBufferSize) {
383                         if (flushAudioBuffer() < 0)
384                                 return -1;
385                 }
386         }
388         return 0;
391 int isAudioDeviceOpen(void)
393         return audioOpened;
396 void dropBufferedAudio(void)
398         int i;
400         syncAudioDeviceStates();
401         audioBufferPos = 0;
403         for (i = 0; i < audioOutputArraySize; ++i) {
404                 if (audioDeviceStates[i] == DEVICE_ON)
405                         dropBufferedAudioOutput(&audioOutputArray[i]);
406         }
409 void closeAudioDevice(void)
411         int i;
413         flushAudioBuffer();
415         free(audioBuffer);
416         audioBuffer = NULL;
417         audioBufferSize = 0;
419         for (i = 0; i < audioOutputArraySize; ++i) {
420                 if (audioDeviceStates[i] == DEVICE_ON)
421                         audioDeviceStates[i] = DEVICE_ENABLE;
422                 closeAudioOutput(&audioOutputArray[i]);
423         }
425         audioOpened = 0;
428 void sendMetadataToAudioDevice(MpdTag * tag)
430         int i;
432         for (i = 0; i < audioOutputArraySize; ++i) {
433                 sendMetadataToAudioOutput(&audioOutputArray[i], tag);
434         }
437 int enableAudioDevice(int fd, int device)
439         if (device < 0 || device >= audioOutputArraySize) {
440                 commandError(fd, ACK_ERROR_ARG, "audio output device id %i "
441                              "doesn't exist\n", device);
442                 return -1;
443         }
445         if (!(audioDeviceStates[device] & 0x01))
446                 audioDeviceStates[device] = DEVICE_ENABLE;
448         return 0;
451 int disableAudioDevice(int fd, int device)
453         if (device < 0 || device >= audioOutputArraySize) {
454                 commandError(fd, ACK_ERROR_ARG, "audio output device id %i "
455                              "doesn't exist\n", device);
456                 return -1;
457         }
458         if (audioDeviceStates[device] & 0x01)
459                 audioDeviceStates[device] = DEVICE_DISABLE;
461         return 0;
464 void printAudioDevices(int fd)
466         int i;
468         for (i = 0; i < audioOutputArraySize; i++) {
469                 fdprintf(fd,
470                          "outputid: %i\noutputname: %s\noutputenabled: %i\n",
471                          i,
472                          audioOutputArray[i].name,
473                          audioDeviceStates[i] & 0x01);
474         }
477 void saveAudioDevicesState(FILE *fp)
479         int i;
481         assert(audioOutputArraySize != 0);
482         for (i = 0; i < audioOutputArraySize; i++) {
483                 fprintf(fp, AUDIO_DEVICE_STATE "%d:%s\n",
484                         audioDeviceStates[i] & 0x01,
485                         audioOutputArray[i].name);
486         }
489 void readAudioDevicesState(FILE *fp)
491         char buffer[AUDIO_BUFFER_SIZE];
492         int i;
494         assert(audioOutputArraySize != 0);
496         while (myFgets(buffer, AUDIO_BUFFER_SIZE, fp)) {
497                 char *c, *name;
499                 if (strncmp(buffer, AUDIO_DEVICE_STATE, AUDIO_DEVICE_STATE_LEN))
500                         continue;
502                 c = strchr(buffer, ':');
503                 if (!c || !(++c))
504                         goto errline;
506                 name = strchr(c, ':');
507                 if (!name || !(++name))
508                         goto errline;
510                 for (i = 0; i < audioOutputArraySize; ++i) {
511                         if (!strcmp(name, audioOutputArray[i].name)) {
512                                 /* devices default to on */
513                                 if (!atoi(c))
514                                         audioDeviceStates[i] = DEVICE_DISABLE;
515                                 break;
516                         }
517                 }
518                 continue;
519 errline:
520                 /* nonfatal */
521                 ERROR("invalid line in state_file: %s\n", buffer);
522         }