Initial revision 6759
[qball-mpd.git] / src / audioOutputs / .svn / text-base / audioOutput_ao.c.svn-base
bloba7f437ef468733e23567d03407d3fee4384eaba1
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 "../audioOutput.h"
21 #ifdef HAVE_AO
23 #include "../conf.h"
24 #include "../log.h"
26 #include <string.h>
28 #include <ao/ao.h>
30 static int driverInitCount;
32 typedef struct _AoData {
33         int writeSize;
34         int driverId;
35         ao_option *options;
36         ao_device *device;
37 } AoData;
39 static AoData *newAoData(void)
41         AoData *ret = xmalloc(sizeof(AoData));
42         ret->device = NULL;
43         ret->options = NULL;
45         return ret;
48 static void audioOutputAo_error(void)
50         if (errno == AO_ENOTLIVE) {
51                 ERROR("not a live ao device\n");
52         } else if (errno == AO_EOPENDEVICE) {
53                 ERROR("not able to open audio device\n");
54         } else if (errno == AO_EBADOPTION) {
55                 ERROR("bad driver option\n");
56         }
59 static int audioOutputAo_initDriver(AudioOutput * audioOutput,
60                                     ConfigParam * param)
62         ao_info *ai;
63         char *dup;
64         char *stk1;
65         char *stk2;
66         char *n1;
67         char *key;
68         char *value;
69         char *test;
70         AoData *ad = newAoData();
71         BlockParam *blockParam;
73         audioOutput->data = ad;
75         if ((blockParam = getBlockParam(param, "write_size"))) {
76                 ad->writeSize = strtol(blockParam->value, &test, 10);
77                 if (*test != '\0') {
78                         FATAL("\"%s\" is not a valid write size at line %i\n",
79                               blockParam->value, blockParam->line);
80                 }
81         } else
82                 ad->writeSize = 1024;
84         if (driverInitCount == 0) {
85                 ao_initialize();
86         }
87         driverInitCount++;
89         blockParam = getBlockParam(param, "driver");
91         if (!blockParam || 0 == strcmp(blockParam->value, "default")) {
92                 ad->driverId = ao_default_driver_id();
93         } else if ((ad->driverId = ao_driver_id(blockParam->value)) < 0) {
94                 FATAL("\"%s\" is not a valid ao driver at line %i\n",
95                       blockParam->value, blockParam->line);
96         }
98         if ((ai = ao_driver_info(ad->driverId)) == NULL) {
99                 FATAL("problems getting driver info for device defined at line %i\n"
100                       "you may not have permission to the audio device\n", param->line);
101         }
103         DEBUG("using ao driver \"%s\" for \"%s\"\n", ai->short_name,
104               audioOutput->name);
106         blockParam = getBlockParam(param, "options");
108         if (blockParam) {
109                 dup = xstrdup(blockParam->value);
110         } else
111                 dup = xstrdup("");
113         if (strlen(dup)) {
114                 stk1 = NULL;
115                 n1 = strtok_r(dup, ";", &stk1);
116                 while (n1) {
117                         stk2 = NULL;
118                         key = strtok_r(n1, "=", &stk2);
119                         if (!key)
120                                 FATAL("problems parsing options \"%s\"\n", n1);
121                         /*found = 0;
122                            for(i=0;i<ai->option_count;i++) {
123                            if(strcmp(ai->options[i],key)==0) {
124                            found = 1;
125                            break;
126                            }
127                            }
128                            if(!found) {
129                            FATAL("\"%s\" is not an option for "
130                            "\"%s\" ao driver\n",key,
131                            ai->short_name);
132                            } */
133                         value = strtok_r(NULL, "", &stk2);
134                         if (!value)
135                                 FATAL("problems parsing options \"%s\"\n", n1);
136                         ao_append_option(&ad->options, key, value);
137                         n1 = strtok_r(NULL, ";", &stk1);
138                 }
139         }
140         free(dup);
142         return 0;
145 static void freeAoData(AoData * ad)
147         ao_free_options(ad->options);
148         free(ad);
151 static void audioOutputAo_finishDriver(AudioOutput * audioOutput)
153         AoData *ad = (AoData *) audioOutput->data;
154         freeAoData(ad);
156         driverInitCount--;
158         if (driverInitCount == 0)
159                 ao_shutdown();
162 static void audioOutputAo_dropBufferedAudio(AudioOutput * audioOutput)
164         /* not supported by libao */
167 static void audioOutputAo_closeDevice(AudioOutput * audioOutput)
169         AoData *ad = (AoData *) audioOutput->data;
171         if (ad->device) {
172                 ao_close(ad->device);
173                 ad->device = NULL;
174         }
176         audioOutput->open = 0;
179 static int audioOutputAo_openDevice(AudioOutput * audioOutput)
181         ao_sample_format format;
182         AoData *ad = (AoData *) audioOutput->data;
184         if (ad->device) {
185                 audioOutputAo_closeDevice(audioOutput);
186         }
188         format.bits = audioOutput->outAudioFormat.bits;
189         format.rate = audioOutput->outAudioFormat.sampleRate;
190         format.byte_format = AO_FMT_NATIVE;
191         format.channels = audioOutput->outAudioFormat.channels;
193         ad->device = ao_open_live(ad->driverId, &format, ad->options);
195         if (ad->device == NULL)
196                 return -1;
198         audioOutput->open = 1;
200         return 0;
203 static int audioOutputAo_play(AudioOutput * audioOutput, char *playChunk,
204                               int size)
206         int send;
207         AoData *ad = (AoData *) audioOutput->data;
209         if (ad->device == NULL)
210                 return -1;
212         while (size > 0) {
213                 send = ad->writeSize > size ? size : ad->writeSize;
215                 if (ao_play(ad->device, playChunk, send) == 0) {
216                         audioOutputAo_error();
217                         ERROR("closing audio device due to write error\n");
218                         audioOutputAo_closeDevice(audioOutput);
219                         return -1;
220                 }
222                 playChunk += send;
223                 size -= send;
224         }
226         return 0;
229 AudioOutputPlugin aoPlugin = {
230         "ao",
231         NULL,
232         audioOutputAo_initDriver,
233         audioOutputAo_finishDriver,
234         audioOutputAo_openDevice,
235         audioOutputAo_play,
236         audioOutputAo_dropBufferedAudio,
237         audioOutputAo_closeDevice,
238         NULL,   /* sendMetadataFunc */
241 #else
243 #include <stdio.h>
245 DISABLED_AUDIO_OUTPUT_PLUGIN(aoPlugin)
246 #endif