12465
|
1 /*
|
28343
|
2 * ALSA 0.9.x-1.x audio output driver
|
|
3 *
|
|
4 * Copyright (C) 2004 Alex Beregszaszi
|
|
5 *
|
|
6 * modified for real ALSA 0.9.0 support by Zsolt Barat <joy@streamminister.de>
|
|
7 * additional AC-3 passthrough support by Andy Lo A Foe <andy@alsaplayer.org>
|
|
8 * 08/22/2002 iec958-init rewritten and merged with common init, zsolt
|
|
9 * 04/13/2004 merged with ao_alsa1.x, fixes provided by Jindrich Makovicka
|
|
10 * 04/25/2004 printfs converted to mp_msg, Zsolt.
|
|
11 *
|
|
12 * This file is part of MPlayer.
|
|
13 *
|
|
14 * MPlayer is free software; you can redistribute it and/or modify
|
|
15 * it under the terms of the GNU General Public License as published by
|
|
16 * the Free Software Foundation; either version 2 of the License, or
|
|
17 * (at your option) any later version.
|
|
18 *
|
|
19 * MPlayer is distributed in the hope that it will be useful,
|
|
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
22 * GNU General Public License for more details.
|
|
23 *
|
|
24 * You should have received a copy of the GNU General Public License along
|
|
25 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
|
26 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
27 */
|
12465
|
28
|
|
29 #include <errno.h>
|
|
30 #include <sys/time.h>
|
|
31 #include <stdlib.h>
|
17691
|
32 #include <stdarg.h>
|
22166
|
33 #include <ctype.h>
|
12465
|
34 #include <math.h>
|
|
35 #include <string.h>
|
27281
|
36 #include <alloca.h>
|
12465
|
37
|
14123
|
38 #include "config.h"
|
14328
|
39 #include "subopt-helper.h"
|
14123
|
40 #include "mixer.h"
|
|
41 #include "mp_msg.h"
|
20764
|
42 #include "help_mp.h"
|
12465
|
43
|
|
44 #define ALSA_PCM_NEW_HW_PARAMS_API
|
|
45 #define ALSA_PCM_NEW_SW_PARAMS_API
|
|
46
|
28362
|
47 #ifdef HAVE_SYS_ASOUNDLIB_H
|
12465
|
48 #include <sys/asoundlib.h>
|
28362
|
49 #elif defined(HAVE_ALSA_ASOUNDLIB_H)
|
12465
|
50 #include <alsa/asoundlib.h>
|
|
51 #else
|
|
52 #error "asoundlib.h is not in sys/ or alsa/ - please bugreport"
|
|
53 #endif
|
|
54
|
|
55
|
|
56 #include "audio_out.h"
|
|
57 #include "audio_out_internal.h"
|
14245
|
58 #include "libaf/af_format.h"
|
12465
|
59
|
29263
|
60 static const ao_info_t info =
|
12465
|
61 {
|
|
62 "ALSA-0.9.x-1.x audio output",
|
|
63 "alsa",
|
|
64 "Alex Beregszaszi, Zsolt Barat <joy@streamminister.de>",
|
|
65 "under developement"
|
|
66 };
|
|
67
|
|
68 LIBAO_EXTERN(alsa)
|
|
69
|
|
70 static snd_pcm_t *alsa_handler;
|
|
71 static snd_pcm_format_t alsa_format;
|
|
72 static snd_pcm_hw_params_t *alsa_hwparams;
|
|
73 static snd_pcm_sw_params_t *alsa_swparams;
|
|
74
|
17619
|
75 static size_t bytes_per_sample;
|
12465
|
76
|
30399
|
77 static int alsa_can_pause;
|
12465
|
78
|
12747
|
79 #define ALSA_DEVICE_SIZE 256
|
12465
|
80
|
17691
|
81 static void alsa_error_handler(const char *file, int line, const char *function,
|
|
82 int err, const char *format, ...)
|
|
83 {
|
|
84 char tmp[0xc00];
|
|
85 va_list va;
|
|
86
|
|
87 va_start(va, format);
|
|
88 vsnprintf(tmp, sizeof tmp, format, va);
|
|
89 va_end(va);
|
|
90 tmp[sizeof tmp - 1] = '\0';
|
|
91
|
|
92 if (err)
|
20764
|
93 mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s: %s\n",
|
17691
|
94 file, line, function, tmp, snd_strerror(err));
|
|
95 else
|
20764
|
96 mp_msg(MSGT_AO, MSGL_ERR, "[AO_ALSA] alsa-lib: %s:%i:(%s) %s\n",
|
17691
|
97 file, line, function, tmp);
|
|
98 }
|
|
99
|
12465
|
100 /* to set/get/query special features/parameters */
|
|
101 static int control(int cmd, void *arg)
|
|
102 {
|
|
103 switch(cmd) {
|
|
104 case AOCONTROL_QUERY_FORMAT:
|
|
105 return CONTROL_TRUE;
|
|
106 case AOCONTROL_GET_VOLUME:
|
|
107 case AOCONTROL_SET_VOLUME:
|
|
108 {
|
|
109 ao_control_vol_t *vol = (ao_control_vol_t *)arg;
|
|
110
|
|
111 int err;
|
|
112 snd_mixer_t *handle;
|
|
113 snd_mixer_elem_t *elem;
|
|
114 snd_mixer_selem_id_t *sid;
|
|
115
|
30400
|
116 char *mix_name = "PCM";
|
|
117 char *card = "default";
|
|
118 int mix_index = 0;
|
12465
|
119
|
|
120 long pmin, pmax;
|
|
121 long get_vol, set_vol;
|
12805
|
122 float f_multi;
|
12465
|
123
|
30234
|
124 if(AF_FORMAT_IS_AC3(ao_data.format))
|
28118
|
125 return CONTROL_TRUE;
|
|
126
|
13434
|
127 if(mixer_channel) {
|
|
128 char *test_mix_index;
|
|
129
|
|
130 mix_name = strdup(mixer_channel);
|
17097
|
131 if ((test_mix_index = strchr(mix_name, ','))){
|
13434
|
132 *test_mix_index = 0;
|
|
133 test_mix_index++;
|
|
134 mix_index = strtol(test_mix_index, &test_mix_index, 0);
|
|
135
|
|
136 if (*test_mix_index){
|
|
137 mp_msg(MSGT_AO,MSGL_ERR,
|
20764
|
138 MSGTR_AO_ALSA_InvalidMixerIndexDefaultingToZero);
|
13434
|
139 mix_index = 0 ;
|
|
140 }
|
|
141 }
|
|
142 }
|
12747
|
143 if(mixer_device) card = mixer_device;
|
12465
|
144
|
|
145 //allocate simple id
|
|
146 snd_mixer_selem_id_alloca(&sid);
|
29263
|
147
|
12465
|
148 //sets simple-mixer index and name
|
13434
|
149 snd_mixer_selem_id_set_index(sid, mix_index);
|
12465
|
150 snd_mixer_selem_id_set_name(sid, mix_name);
|
|
151
|
13434
|
152 if (mixer_channel) {
|
|
153 free(mix_name);
|
|
154 mix_name = NULL;
|
|
155 }
|
|
156
|
12465
|
157 if ((err = snd_mixer_open(&handle, 0)) < 0) {
|
20764
|
158 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerOpenError, snd_strerror(err));
|
12465
|
159 return CONTROL_ERROR;
|
|
160 }
|
|
161
|
|
162 if ((err = snd_mixer_attach(handle, card)) < 0) {
|
29263
|
163 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerAttachError,
|
12465
|
164 card, snd_strerror(err));
|
|
165 snd_mixer_close(handle);
|
|
166 return CONTROL_ERROR;
|
|
167 }
|
|
168
|
|
169 if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
|
20764
|
170 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerRegisterError, snd_strerror(err));
|
12465
|
171 snd_mixer_close(handle);
|
|
172 return CONTROL_ERROR;
|
|
173 }
|
|
174 err = snd_mixer_load(handle);
|
|
175 if (err < 0) {
|
20764
|
176 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_MixerLoadError, snd_strerror(err));
|
12465
|
177 snd_mixer_close(handle);
|
|
178 return CONTROL_ERROR;
|
|
179 }
|
|
180
|
|
181 elem = snd_mixer_find_selem(handle, sid);
|
|
182 if (!elem) {
|
20764
|
183 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToFindSimpleControl,
|
12465
|
184 snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
|
|
185 snd_mixer_close(handle);
|
|
186 return CONTROL_ERROR;
|
|
187 }
|
|
188
|
|
189 snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
|
12811
|
190 f_multi = (100 / (float)(pmax - pmin));
|
12465
|
191
|
|
192 if (cmd == AOCONTROL_SET_VOLUME) {
|
|
193
|
12811
|
194 set_vol = vol->left / f_multi + pmin + 0.5;
|
12465
|
195
|
|
196 //setting channels
|
27706
|
197 if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, set_vol)) < 0) {
|
29263
|
198 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingLeftChannel,
|
12465
|
199 snd_strerror(err));
|
29436
|
200 snd_mixer_close(handle);
|
12465
|
201 return CONTROL_ERROR;
|
|
202 }
|
12805
|
203 mp_msg(MSGT_AO,MSGL_DBG2,"left=%li, ", set_vol);
|
|
204
|
12811
|
205 set_vol = vol->right / f_multi + pmin + 0.5;
|
12805
|
206
|
27706
|
207 if ((err = snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, set_vol)) < 0) {
|
29263
|
208 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSettingRightChannel,
|
12465
|
209 snd_strerror(err));
|
29436
|
210 snd_mixer_close(handle);
|
12465
|
211 return CONTROL_ERROR;
|
|
212 }
|
29263
|
213 mp_msg(MSGT_AO,MSGL_DBG2,"right=%li, pmin=%li, pmax=%li, mult=%f\n",
|
12805
|
214 set_vol, pmin, pmax, f_multi);
|
17194
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
215
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
216 if (snd_mixer_selem_has_playback_switch(elem)) {
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
217 int lmute = (vol->left == 0.0);
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
218 int rmute = (vol->right == 0.0);
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
219 if (snd_mixer_selem_has_playback_switch_joined(elem)) {
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
220 lmute = rmute = lmute && rmute;
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
221 } else {
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
222 snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_RIGHT, !rmute);
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
223 }
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
224 snd_mixer_selem_set_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, !lmute);
|
cd527e59d128
use snd_mixer_selem_set_playback_switch when muting ALSA, patch by Matthias Lederhofer <matled -at- gmx dot net>
wanderer
diff
changeset
|
225 }
|
12465
|
226 }
|
|
227 else {
|
27706
|
228 snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &get_vol);
|
12811
|
229 vol->left = (get_vol - pmin) * f_multi;
|
27706
|
230 snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &get_vol);
|
12811
|
231 vol->right = (get_vol - pmin) * f_multi;
|
12465
|
232
|
12805
|
233 mp_msg(MSGT_AO,MSGL_DBG2,"left=%f, right=%f\n",vol->left,vol->right);
|
12465
|
234 }
|
|
235 snd_mixer_close(handle);
|
|
236 return CONTROL_OK;
|
|
237 }
|
29263
|
238
|
12465
|
239 } //end switch
|
26757
|
240 return CONTROL_UNKNOWN;
|
12465
|
241 }
|
|
242
|
14328
|
243 static void parse_device (char *dest, const char *src, int len)
|
12805
|
244 {
|
|
245 char *tmp;
|
14328
|
246 memmove(dest, src, len);
|
|
247 dest[len] = 0;
|
12805
|
248 while ((tmp = strrchr(dest, '.')))
|
|
249 tmp[0] = ',';
|
12919
|
250 while ((tmp = strrchr(dest, '=')))
|
12805
|
251 tmp[0] = ':';
|
|
252 }
|
|
253
|
17566
|
254 static void print_help (void)
|
12805
|
255 {
|
|
256 mp_msg (MSGT_AO, MSGL_FATAL,
|
20764
|
257 MSGTR_AO_ALSA_CommandlineHelp);
|
12805
|
258 }
|
12465
|
259
|
30122
|
260 static int str_maxlen(void *strp) {
|
|
261 strarg_t *str = strp;
|
30123
|
262 return str->len <= ALSA_DEVICE_SIZE;
|
14328
|
263 }
|
|
264
|
22166
|
265 static int try_open_device(const char *device, int open_mode, int try_ac3)
|
19889
|
266 {
|
22166
|
267 int err, len;
|
|
268 char *ac3_device, *args;
|
19889
|
269
|
22166
|
270 if (try_ac3) {
|
|
271 /* to set the non-audio bit, use AES0=6 */
|
|
272 len = strlen(device);
|
|
273 ac3_device = malloc(len + 7 + 1);
|
|
274 if (!ac3_device)
|
|
275 return -ENOMEM;
|
|
276 strcpy(ac3_device, device);
|
|
277 args = strchr(ac3_device, ':');
|
|
278 if (!args) {
|
|
279 /* no existing parameters: add it behind device name */
|
|
280 strcat(ac3_device, ":AES0=6");
|
|
281 } else {
|
|
282 do
|
|
283 ++args;
|
|
284 while (isspace(*args));
|
|
285 if (*args == '\0') {
|
|
286 /* ":" but no parameters */
|
|
287 strcat(ac3_device, "AES0=6");
|
|
288 } else if (*args != '{') {
|
|
289 /* a simple list of parameters: add it at the end of the list */
|
|
290 strcat(ac3_device, ",AES0=6");
|
|
291 } else {
|
|
292 /* parameters in config syntax: add it inside the { } block */
|
|
293 do
|
|
294 --len;
|
|
295 while (len > 0 && isspace(ac3_device[len]));
|
|
296 if (ac3_device[len] == '}')
|
|
297 strcpy(ac3_device + len, " AES0=6}");
|
19889
|
298 }
|
|
299 }
|
22166
|
300 err = snd_pcm_open(&alsa_handler, ac3_device, SND_PCM_STREAM_PLAYBACK,
|
|
301 open_mode);
|
|
302 free(ac3_device);
|
19889
|
303 }
|
22166
|
304 if (!try_ac3 || err < 0)
|
|
305 err = snd_pcm_open(&alsa_handler, device, SND_PCM_STREAM_PLAYBACK,
|
|
306 open_mode);
|
|
307 return err;
|
19889
|
308 }
|
|
309
|
12465
|
310 /*
|
|
311 open & setup audio device
|
|
312 return: 1=success 0=fail
|
|
313 */
|
|
314 static int init(int rate_hz, int channels, int format, int flags)
|
|
315 {
|
30398
|
316 unsigned int alsa_buffer_time = 500000; /* 0.5 s */
|
|
317 unsigned int alsa_fragcount = 16;
|
12465
|
318 int err;
|
14328
|
319 int block;
|
|
320 strarg_t device;
|
29507
|
321 snd_pcm_uframes_t chunk_size;
|
12465
|
322 snd_pcm_uframes_t bufsize;
|
17620
|
323 snd_pcm_uframes_t boundary;
|
29586
|
324 const opt_t subopts[] = {
|
14328
|
325 {"block", OPT_ARG_BOOL, &block, NULL},
|
30122
|
326 {"device", OPT_ARG_STR, &device, str_maxlen},
|
14328
|
327 {NULL}
|
|
328 };
|
|
329
|
12747
|
330 char alsa_device[ALSA_DEVICE_SIZE + 1];
|
|
331 // make sure alsa_device is null-terminated even when using strncpy etc.
|
|
332 memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1);
|
12465
|
333
|
14249
|
334 mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz,
|
|
335 channels, format);
|
12465
|
336 alsa_handler = NULL;
|
17690
|
337 #if SND_LIB_VERSION >= 0x010005
|
|
338 mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version());
|
|
339 #else
|
12465
|
340 mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR);
|
17690
|
341 #endif
|
17691
|
342
|
|
343 snd_lib_error_set_handler(alsa_error_handler);
|
29263
|
344
|
12465
|
345 ao_data.samplerate = rate_hz;
|
|
346 ao_data.format = format;
|
|
347 ao_data.channels = channels;
|
|
348
|
|
349 switch (format)
|
|
350 {
|
14245
|
351 case AF_FORMAT_S8:
|
12465
|
352 alsa_format = SND_PCM_FORMAT_S8;
|
|
353 break;
|
14245
|
354 case AF_FORMAT_U8:
|
12465
|
355 alsa_format = SND_PCM_FORMAT_U8;
|
|
356 break;
|
14245
|
357 case AF_FORMAT_U16_LE:
|
12465
|
358 alsa_format = SND_PCM_FORMAT_U16_LE;
|
|
359 break;
|
14245
|
360 case AF_FORMAT_U16_BE:
|
12465
|
361 alsa_format = SND_PCM_FORMAT_U16_BE;
|
|
362 break;
|
30241
|
363 case AF_FORMAT_AC3_LE:
|
14245
|
364 case AF_FORMAT_S16_LE:
|
12465
|
365 alsa_format = SND_PCM_FORMAT_S16_LE;
|
|
366 break;
|
30241
|
367 case AF_FORMAT_AC3_BE:
|
14245
|
368 case AF_FORMAT_S16_BE:
|
12465
|
369 alsa_format = SND_PCM_FORMAT_S16_BE;
|
|
370 break;
|
17571
|
371 case AF_FORMAT_U32_LE:
|
|
372 alsa_format = SND_PCM_FORMAT_U32_LE;
|
|
373 break;
|
|
374 case AF_FORMAT_U32_BE:
|
|
375 alsa_format = SND_PCM_FORMAT_U32_BE;
|
|
376 break;
|
14245
|
377 case AF_FORMAT_S32_LE:
|
12465
|
378 alsa_format = SND_PCM_FORMAT_S32_LE;
|
|
379 break;
|
14245
|
380 case AF_FORMAT_S32_BE:
|
12465
|
381 alsa_format = SND_PCM_FORMAT_S32_BE;
|
|
382 break;
|
29386
|
383 case AF_FORMAT_U24_LE:
|
29392
|
384 alsa_format = SND_PCM_FORMAT_U24_3LE;
|
29386
|
385 break;
|
|
386 case AF_FORMAT_U24_BE:
|
29392
|
387 alsa_format = SND_PCM_FORMAT_U24_3BE;
|
29386
|
388 break;
|
|
389 case AF_FORMAT_S24_LE:
|
29392
|
390 alsa_format = SND_PCM_FORMAT_S24_3LE;
|
29386
|
391 break;
|
|
392 case AF_FORMAT_S24_BE:
|
29392
|
393 alsa_format = SND_PCM_FORMAT_S24_3BE;
|
29386
|
394 break;
|
14245
|
395 case AF_FORMAT_FLOAT_LE:
|
12570
|
396 alsa_format = SND_PCM_FORMAT_FLOAT_LE;
|
|
397 break;
|
17571
|
398 case AF_FORMAT_FLOAT_BE:
|
|
399 alsa_format = SND_PCM_FORMAT_FLOAT_BE;
|
|
400 break;
|
|
401 case AF_FORMAT_MU_LAW:
|
|
402 alsa_format = SND_PCM_FORMAT_MU_LAW;
|
|
403 break;
|
|
404 case AF_FORMAT_A_LAW:
|
|
405 alsa_format = SND_PCM_FORMAT_A_LAW;
|
|
406 break;
|
12465
|
407
|
|
408 default:
|
14251
|
409 alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1
|
12465
|
410 break;
|
|
411 }
|
29263
|
412
|
12805
|
413 //subdevice parsing
|
14328
|
414 // set defaults
|
|
415 block = 1;
|
12465
|
416 /* switch for spdif
|
|
417 * sets opening sequence for SPDIF
|
|
418 * sets also the playback and other switches 'on the fly'
|
|
419 * while opening the abstract alias for the spdif subdevice
|
|
420 * 'iec958'
|
|
421 */
|
30234
|
422 if (AF_FORMAT_IS_AC3(format)) {
|
19889
|
423 device.str = "iec958";
|
12747
|
424 mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3, %i channels\n", channels);
|
12465
|
425 }
|
13661
|
426 else
|
14328
|
427 /* in any case for multichannel playback we should select
|
|
428 * appropriate device
|
|
429 */
|
|
430 switch (channels) {
|
|
431 case 1:
|
|
432 case 2:
|
|
433 device.str = "default";
|
|
434 mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n");
|
|
435 break;
|
|
436 case 4:
|
|
437 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
|
|
438 // hack - use the converter plugin
|
|
439 device.str = "plug:surround40";
|
|
440 else
|
|
441 device.str = "surround40";
|
|
442 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n");
|
|
443 break;
|
|
444 case 6:
|
|
445 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
|
|
446 device.str = "plug:surround51";
|
|
447 else
|
|
448 device.str = "surround51";
|
|
449 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n");
|
|
450 break;
|
29826
|
451 case 8:
|
|
452 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
|
|
453 device.str = "plug:surround71";
|
|
454 else
|
|
455 device.str = "surround71";
|
|
456 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround71\n");
|
|
457 break;
|
14328
|
458 default:
|
|
459 device.str = "default";
|
20764
|
460 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ChannelsNotSupported,channels);
|
14328
|
461 }
|
|
462 device.len = strlen(device.str);
|
|
463 if (subopt_parse(ao_subdevice, subopts) != 0) {
|
|
464 print_help();
|
|
465 return 0;
|
|
466 }
|
|
467 parse_device(alsa_device, device.str, device.len);
|
12465
|
468
|
20185
|
469 mp_msg(MSGT_AO,MSGL_V,"alsa-init: using device %s\n", alsa_device);
|
12465
|
470
|
|
471 if (!alsa_handler) {
|
30402
|
472 int open_mode = block ? 0 : SND_PCM_NONBLOCK;
|
30234
|
473 int isac3 = AF_FORMAT_IS_AC3(format);
|
12465
|
474 //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
|
30234
|
475 if ((err = try_open_device(alsa_device, open_mode, isac3)) < 0)
|
12465
|
476 {
|
30401
|
477 if (err != -EBUSY && !block) {
|
20764
|
478 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_OpenInNonblockModeFailed);
|
30234
|
479 if ((err = try_open_device(alsa_device, 0, isac3)) < 0) {
|
20764
|
480 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err));
|
26757
|
481 return 0;
|
12465
|
482 }
|
|
483 } else {
|
20764
|
484 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err));
|
26757
|
485 return 0;
|
12465
|
486 }
|
|
487 }
|
|
488
|
17619
|
489 if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) {
|
20764
|
490 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSetBlockMode, snd_strerror(err));
|
12465
|
491 } else {
|
20743
|
492 mp_msg(MSGT_AO,MSGL_V,"alsa-init: pcm opened in blocking mode\n");
|
12465
|
493 }
|
|
494
|
|
495 snd_pcm_hw_params_alloca(&alsa_hwparams);
|
|
496 snd_pcm_sw_params_alloca(&alsa_swparams);
|
|
497
|
|
498 // setting hw-parameters
|
|
499 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0)
|
|
500 {
|
20764
|
501 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetInitialParameters,
|
12465
|
502 snd_strerror(err));
|
26757
|
503 return 0;
|
12465
|
504 }
|
29263
|
505
|
17616
|
506 err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
|
|
507 SND_PCM_ACCESS_RW_INTERLEAVED);
|
12465
|
508 if (err < 0) {
|
29263
|
509 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetAccessType,
|
12465
|
510 snd_strerror(err));
|
26757
|
511 return 0;
|
12465
|
512 }
|
|
513
|
|
514 /* workaround for nonsupported formats
|
|
515 sets default format to S16_LE if the given formats aren't supported */
|
|
516 if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams,
|
|
517 alsa_format)) < 0)
|
|
518 {
|
|
519 mp_msg(MSGT_AO,MSGL_INFO,
|
20764
|
520 MSGTR_AO_ALSA_FormatNotSupportedByHardware, af_fmt2str_short(format));
|
12465
|
521 alsa_format = SND_PCM_FORMAT_S16_LE;
|
30241
|
522 if (AF_FORMAT_IS_AC3(ao_data.format))
|
|
523 ao_data.format = AF_FORMAT_AC3_LE;
|
|
524 else
|
14245
|
525 ao_data.format = AF_FORMAT_S16_LE;
|
12465
|
526 }
|
|
527
|
|
528 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
|
|
529 alsa_format)) < 0)
|
|
530 {
|
20764
|
531 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetFormat,
|
12465
|
532 snd_strerror(err));
|
26757
|
533 return 0;
|
12465
|
534 }
|
|
535
|
16308
|
536 if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams,
|
|
537 &ao_data.channels)) < 0)
|
12465
|
538 {
|
20764
|
539 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetChannels,
|
12465
|
540 snd_strerror(err));
|
26757
|
541 return 0;
|
12465
|
542 }
|
|
543
|
17849
|
544 /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11)
|
30410
|
545 prefer our own resampler, since that allows users to choose the resampler,
|
|
546 even per file if desired */
|
17849
|
547 #if SND_LIB_VERSION >= 0x010009
|
|
548 if ((err = snd_pcm_hw_params_set_rate_resample(alsa_handler, alsa_hwparams,
|
|
549 0)) < 0)
|
|
550 {
|
20764
|
551 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToDisableResampling,
|
17849
|
552 snd_strerror(err));
|
26757
|
553 return 0;
|
17849
|
554 }
|
|
555 #endif
|
|
556
|
29263
|
557 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams,
|
|
558 &ao_data.samplerate, NULL)) < 0)
|
12465
|
559 {
|
20764
|
560 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSamplerate2,
|
12465
|
561 snd_strerror(err));
|
26757
|
562 return 0;
|
12465
|
563 }
|
|
564
|
30237
|
565 bytes_per_sample = af_fmt2bits(ao_data.format) / 8;
|
17570
|
566 bytes_per_sample *= ao_data.channels;
|
|
567 ao_data.bps = ao_data.samplerate * bytes_per_sample;
|
16309
|
568
|
29263
|
569 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams,
|
17575
|
570 &alsa_buffer_time, NULL)) < 0)
|
12465
|
571 {
|
20764
|
572 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetBufferTimeNear,
|
12465
|
573 snd_strerror(err));
|
26757
|
574 return 0;
|
29507
|
575 }
|
12465
|
576
|
|
577 if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams,
|
17575
|
578 &alsa_fragcount, NULL)) < 0) {
|
29263
|
579 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriods,
|
12465
|
580 snd_strerror(err));
|
19887
|
581 return 0;
|
12465
|
582 }
|
|
583
|
|
584 /* finally install hardware parameters */
|
|
585 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
|
|
586 {
|
20764
|
587 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetHwParameters,
|
12465
|
588 snd_strerror(err));
|
19887
|
589 return 0;
|
12465
|
590 }
|
|
591 // end setting hw-params
|
|
592
|
|
593
|
|
594 // gets buffersize for control
|
|
595 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0)
|
|
596 {
|
20764
|
597 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBufferSize, snd_strerror(err));
|
19887
|
598 return 0;
|
12465
|
599 }
|
|
600 else {
|
|
601 ao_data.buffersize = bufsize * bytes_per_sample;
|
|
602 mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize);
|
|
603 }
|
|
604
|
17620
|
605 if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL)) < 0) {
|
20764
|
606 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetPeriodSize, snd_strerror(err));
|
19887
|
607 return 0;
|
17620
|
608 } else {
|
|
609 mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n", chunk_size);
|
|
610 }
|
|
611 ao_data.outburst = chunk_size * bytes_per_sample;
|
|
612
|
|
613 /* setting software parameters */
|
|
614 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) {
|
20764
|
615 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters,
|
17620
|
616 snd_strerror(err));
|
|
617 return 0;
|
|
618 }
|
18009
|
619 #if SND_LIB_VERSION >= 0x000901
|
17620
|
620 if ((err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary)) < 0) {
|
20764
|
621 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBoundary,
|
17620
|
622 snd_strerror(err));
|
|
623 return 0;
|
|
624 }
|
18009
|
625 #else
|
|
626 boundary = 0x7fffffff;
|
|
627 #endif
|
17620
|
628 /* start playing when one period has been written */
|
|
629 if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, chunk_size)) < 0) {
|
20764
|
630 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStartThreshold,
|
17620
|
631 snd_strerror(err));
|
|
632 return 0;
|
|
633 }
|
|
634 /* disable underrun reporting */
|
|
635 if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, boundary)) < 0) {
|
20764
|
636 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStopThreshold,
|
17620
|
637 snd_strerror(err));
|
|
638 return 0;
|
|
639 }
|
18009
|
640 #if SND_LIB_VERSION >= 0x000901
|
17620
|
641 /* play silence when there is an underrun */
|
|
642 if ((err = snd_pcm_sw_params_set_silence_size(alsa_handler, alsa_swparams, boundary)) < 0) {
|
20764
|
643 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSilenceSize,
|
17620
|
644 snd_strerror(err));
|
|
645 return 0;
|
|
646 }
|
18009
|
647 #endif
|
17620
|
648 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) {
|
20764
|
649 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters,
|
17620
|
650 snd_strerror(err));
|
|
651 return 0;
|
|
652 }
|
|
653 /* end setting sw-params */
|
|
654
|
20185
|
655 mp_msg(MSGT_AO,MSGL_V,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
|
27682
|
656 ao_data.samplerate, ao_data.channels, (int)bytes_per_sample, ao_data.buffersize,
|
12465
|
657 snd_pcm_format_description(alsa_format));
|
|
658
|
|
659 } // end switch alsa_handler (spdif)
|
|
660 alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
|
26757
|
661 return 1;
|
12465
|
662 } // end init
|
|
663
|
|
664
|
|
665 /* close audio device */
|
|
666 static void uninit(int immed)
|
|
667 {
|
|
668
|
|
669 if (alsa_handler) {
|
|
670 int err;
|
|
671
|
14849
|
672 if (!immed)
|
|
673 snd_pcm_drain(alsa_handler);
|
|
674
|
12465
|
675 if ((err = snd_pcm_close(alsa_handler)) < 0)
|
|
676 {
|
20764
|
677 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmCloseError, snd_strerror(err));
|
12465
|
678 return;
|
|
679 }
|
|
680 else {
|
|
681 alsa_handler = NULL;
|
20185
|
682 mp_msg(MSGT_AO,MSGL_V,"alsa-uninit: pcm closed\n");
|
12465
|
683 }
|
|
684 }
|
|
685 else {
|
20764
|
686 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_NoHandlerDefined);
|
12465
|
687 }
|
|
688 }
|
|
689
|
17566
|
690 static void audio_pause(void)
|
12465
|
691 {
|
|
692 int err;
|
|
693
|
|
694 if (alsa_can_pause) {
|
|
695 if ((err = snd_pcm_pause(alsa_handler, 1)) < 0)
|
|
696 {
|
20764
|
697 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPauseError, snd_strerror(err));
|
12465
|
698 return;
|
|
699 }
|
|
700 mp_msg(MSGT_AO,MSGL_V,"alsa-pause: pause supported by hardware\n");
|
|
701 } else {
|
|
702 if ((err = snd_pcm_drop(alsa_handler)) < 0)
|
|
703 {
|
20764
|
704 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmDropError, snd_strerror(err));
|
12465
|
705 return;
|
|
706 }
|
|
707 }
|
|
708 }
|
|
709
|
17566
|
710 static void audio_resume(void)
|
12465
|
711 {
|
|
712 int err;
|
|
713
|
27680
a529f3763afa
Make alsa resume after suspend to disk (would say 'file descriptor is in bad state' before this change)
ranma
diff
changeset
|
714 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
|
a529f3763afa
Make alsa resume after suspend to disk (would say 'file descriptor is in bad state' before this change)
ranma
diff
changeset
|
715 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_PcmInSuspendModeTryingResume);
|
a529f3763afa
Make alsa resume after suspend to disk (would say 'file descriptor is in bad state' before this change)
ranma
diff
changeset
|
716 while ((err = snd_pcm_resume(alsa_handler)) == -EAGAIN) sleep(1);
|
a529f3763afa
Make alsa resume after suspend to disk (would say 'file descriptor is in bad state' before this change)
ranma
diff
changeset
|
717 }
|
12465
|
718 if (alsa_can_pause) {
|
|
719 if ((err = snd_pcm_pause(alsa_handler, 0)) < 0)
|
|
720 {
|
20764
|
721 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmResumeError, snd_strerror(err));
|
12465
|
722 return;
|
|
723 }
|
|
724 mp_msg(MSGT_AO,MSGL_V,"alsa-resume: resume supported by hardware\n");
|
|
725 } else {
|
|
726 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
|
|
727 {
|
20764
|
728 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err));
|
12465
|
729 return;
|
|
730 }
|
|
731 }
|
|
732 }
|
|
733
|
|
734 /* stop playing and empty buffers (for seeking/pause) */
|
17566
|
735 static void reset(void)
|
12465
|
736 {
|
|
737 int err;
|
|
738
|
|
739 if ((err = snd_pcm_drop(alsa_handler)) < 0)
|
|
740 {
|
20764
|
741 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err));
|
12465
|
742 return;
|
|
743 }
|
|
744 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
|
|
745 {
|
20764
|
746 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(err));
|
12465
|
747 return;
|
|
748 }
|
|
749 return;
|
|
750 }
|
|
751
|
|
752 /*
|
|
753 plays 'len' bytes of 'data'
|
|
754 returns: number of bytes played
|
|
755 modified last at 29.06.02 by jp
|
|
756 thanxs for marius <marius@rospot.com> for giving us the light ;)
|
|
757 */
|
|
758
|
17617
|
759 static int play(void* data, int len, int flags)
|
12465
|
760 {
|
29706
|
761 int num_frames;
|
12465
|
762 snd_pcm_sframes_t res = 0;
|
29706
|
763 if (!(flags & AOPLAY_FINAL_CHUNK))
|
|
764 len = len / ao_data.outburst * ao_data.outburst;
|
|
765 num_frames = len / bytes_per_sample;
|
12465
|
766
|
|
767 //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len);
|
|
768
|
|
769 if (!alsa_handler) {
|
20764
|
770 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_DeviceConfigurationError);
|
12465
|
771 return 0;
|
|
772 }
|
|
773
|
17621
|
774 if (num_frames == 0)
|
|
775 return 0;
|
|
776
|
|
777 do {
|
|
778 res = snd_pcm_writei(alsa_handler, data, num_frames);
|
12465
|
779
|
17621
|
780 if (res == -EINTR) {
|
|
781 /* nothing to do */
|
|
782 res = 0;
|
|
783 }
|
|
784 else if (res == -ESTRPIPE) { /* suspend */
|
20764
|
785 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_PcmInSuspendModeTryingResume);
|
12465
|
786 while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN)
|
|
787 sleep(1);
|
|
788 }
|
17621
|
789 if (res < 0) {
|
20764
|
790 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_WriteError, snd_strerror(res));
|
|
791 mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_TryingToResetSoundcard);
|
12465
|
792 if ((res = snd_pcm_prepare(alsa_handler)) < 0) {
|
20764
|
793 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PcmPrepareError, snd_strerror(res));
|
26757
|
794 return 0;
|
12465
|
795 break;
|
|
796 }
|
|
797 }
|
17621
|
798 } while (res == 0);
|
12465
|
799
|
17621
|
800 return res < 0 ? res : res * bytes_per_sample;
|
12465
|
801 }
|
|
802
|
|
803 /* how many byes are free in the buffer */
|
17566
|
804 static int get_space(void)
|
12465
|
805 {
|
|
806 snd_pcm_status_t *status;
|
|
807 int ret;
|
29263
|
808
|
12747
|
809 snd_pcm_status_alloca(&status);
|
29263
|
810
|
12465
|
811 if ((ret = snd_pcm_status(alsa_handler, status)) < 0)
|
|
812 {
|
20764
|
813 mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_CannotGetPcmStatus, snd_strerror(ret));
|
26757
|
814 return 0;
|
12465
|
815 }
|
29263
|
816
|
17572
|
817 ret = snd_pcm_status_get_avail(status) * bytes_per_sample;
|
24590
|
818 if (ret > ao_data.buffersize) // Buffer underrun?
|
|
819 ret = ao_data.buffersize;
|
26757
|
820 return ret;
|
12465
|
821 }
|
|
822
|
|
823 /* delay in seconds between first and last sample in buffer */
|
17566
|
824 static float get_delay(void)
|
12465
|
825 {
|
|
826 if (alsa_handler) {
|
17573
|
827 snd_pcm_sframes_t delay;
|
29263
|
828
|
17573
|
829 if (snd_pcm_delay(alsa_handler, &delay) < 0)
|
|
830 return 0;
|
29263
|
831
|
17573
|
832 if (delay < 0) {
|
|
833 /* underrun - move the application pointer forward to catch up */
|
|
834 #if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */
|
|
835 snd_pcm_forward(alsa_handler, -delay);
|
|
836 #endif
|
|
837 delay = 0;
|
12465
|
838 }
|
17573
|
839 return (float)delay / (float)ao_data.samplerate;
|
12465
|
840 } else {
|
26757
|
841 return 0;
|
12465
|
842 }
|
|
843 }
|