Handle streams separately in tree_add_track()
[cmus.git] / ao.c
blob7acd7a91c880fad7d78b93a11c152d5c09ef3f0f
1 /*
2 * Copyright 2006 Johannes Weißl
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * 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
17 * 02111-1307, USA.
20 #include "op.h"
21 #include "xmalloc.h"
22 #include "utils.h"
23 #include "misc.h"
26 * <ao/ao.h> uses FILE but doesn't include stdio.h.
27 * Also we use snprintf().
29 #include <stdio.h>
30 #include <ao/ao.h>
32 static ao_device *libao_device;
33 static char *wav_dir = NULL;
34 static int wav_counter = 1;
35 static int is_wav = 0;
37 /* configuration */
38 static char *libao_driver = NULL;
39 static int libao_buffer_space = 8192;
42 static int op_ao_init(void)
44 /* ignore config value */
45 wav_counter = 1;
47 ao_initialize();
48 return 0;
51 static int op_ao_exit(void)
53 free(libao_driver);
54 ao_shutdown();
55 return 0;
58 static int op_ao_open(sample_format_t sf)
60 ao_sample_format format;
61 int driver;
63 if (libao_driver == NULL) {
64 driver = ao_default_driver_id();
65 } else {
66 driver = ao_driver_id(libao_driver);
67 is_wav = strcasecmp(libao_driver, "wav") == 0;
69 if (driver == -1) {
70 errno = ENODEV;
71 return -OP_ERROR_ERRNO;
74 format.bits = sf_get_bits(sf);
75 format.rate = sf_get_rate(sf);
76 format.channels = sf_get_channels(sf);
77 format.byte_format = sf_get_bigendian(sf) ? AO_FMT_BIG : AO_FMT_LITTLE;
79 if (is_wav) {
80 char file[512];
82 if (wav_dir == NULL)
83 wav_dir = xstrdup(home_dir);
84 snprintf(file, sizeof(file), "%s/%02d.wav", wav_dir, wav_counter);
85 libao_device = ao_open_file(driver, file, 0, &format, NULL);
86 } else {
87 libao_device = ao_open_live(driver, &format, NULL);
90 if (libao_device == NULL) {
91 switch (errno) {
92 case AO_ENODRIVER:
93 case AO_ENOTFILE:
94 case AO_ENOTLIVE:
95 case AO_EOPENDEVICE:
96 errno = ENODEV;
97 return -OP_ERROR_ERRNO;
98 case AO_EBADOPTION:
99 errno = EINVAL;
100 return -OP_ERROR_ERRNO;
101 case AO_EOPENFILE:
102 errno = EACCES;
103 return -OP_ERROR_ERRNO;
104 case AO_EFILEEXISTS:
105 errno = EEXIST;
106 return -OP_ERROR_ERRNO;
107 case AO_EFAIL:
108 default:
109 return -OP_ERROR_INTERNAL;
112 return 0;
115 static int op_ao_close(void)
117 ao_close(libao_device);
118 if (is_wav)
119 wav_counter++;
120 return 0;
123 static int op_ao_write(const char *buffer, int count)
125 if (ao_play(libao_device, (void *)buffer, count) == 0)
126 return -1;
127 return count;
130 static int op_ao_buffer_space(void)
132 if (is_wav)
133 return 128 * 1024;
134 return libao_buffer_space;
137 static int op_ao_set_option(int key, const char *val)
139 long int ival;
141 switch (key) {
142 case 0:
143 if (str_to_int(val, &ival) || ival < 4096) {
144 errno = EINVAL;
145 return -OP_ERROR_ERRNO;
147 libao_buffer_space = ival;
148 break;
149 case 1:
150 free(libao_driver);
151 libao_driver = NULL;
152 if (val[0])
153 libao_driver = xstrdup(val);
154 break;
155 case 2:
156 if (str_to_int(val, &ival)) {
157 errno = EINVAL;
158 return -OP_ERROR_ERRNO;
160 wav_counter = ival;
161 break;
162 case 3:
163 free(wav_dir);
164 wav_dir = xstrdup(val);
165 break;
166 default:
167 return -OP_ERROR_NOT_OPTION;
169 return 0;
172 static int op_ao_get_option(int key, char **val)
174 switch (key) {
175 case 0:
176 *val = xnew(char, 22);
177 snprintf(*val, 22, "%d", libao_buffer_space);
178 break;
179 case 1:
180 if (libao_driver)
181 *val = xstrdup(libao_driver);
182 break;
183 case 2:
184 *val = xnew(char, 22);
185 snprintf(*val, 22, "%d", wav_counter);
186 break;
187 case 3:
188 if (wav_dir == NULL)
189 wav_dir = xstrdup(home_dir);
190 *val = xstrdup(wav_dir);
191 break;
192 default:
193 return -OP_ERROR_NOT_OPTION;
195 return 0;
198 const struct output_plugin_ops op_pcm_ops = {
199 .init = op_ao_init,
200 .exit = op_ao_exit,
201 .open = op_ao_open,
202 .close = op_ao_close,
203 .write = op_ao_write,
204 .buffer_space = op_ao_buffer_space,
205 .set_option = op_ao_set_option,
206 .get_option = op_ao_get_option
209 const char * const op_pcm_options[] = {
210 "buffer_size",
211 "driver",
212 "wav_counter",
213 "wav_dir",
214 NULL
217 const int op_priority = 3;