12465
|
1 /*
|
|
2 ao_alsa9/1.x - ALSA-0.9.x-1.x output plugin for MPlayer
|
|
3
|
|
4 (C) Alex Beregszaszi
|
|
5
|
|
6 modified for real alsa-0.9.0-support by Zsolt Barat <joy@streamminister.de>
|
|
7 additional AC3 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 Any bugreports regarding to this driver are welcome.
|
|
13 */
|
|
14
|
|
15 #include <errno.h>
|
|
16 #include <sys/time.h>
|
|
17 #include <stdlib.h>
|
|
18 #include <math.h>
|
|
19 #include <string.h>
|
|
20 #include <sys/poll.h>
|
|
21
|
|
22 #include "../config.h"
|
|
23 #include "../mixer.h"
|
|
24 #include "../mp_msg.h"
|
|
25
|
|
26 #define ALSA_PCM_NEW_HW_PARAMS_API
|
|
27 #define ALSA_PCM_NEW_SW_PARAMS_API
|
|
28
|
|
29 #if HAVE_SYS_ASOUNDLIB_H
|
|
30 #include <sys/asoundlib.h>
|
|
31 #elif HAVE_ALSA_ASOUNDLIB_H
|
|
32 #include <alsa/asoundlib.h>
|
|
33 #else
|
|
34 #error "asoundlib.h is not in sys/ or alsa/ - please bugreport"
|
|
35 #endif
|
|
36
|
|
37
|
|
38 #include "audio_out.h"
|
|
39 #include "audio_out_internal.h"
|
|
40 #include "afmt.h"
|
|
41
|
|
42 static ao_info_t info =
|
|
43 {
|
|
44 "ALSA-0.9.x-1.x audio output",
|
|
45 "alsa",
|
|
46 "Alex Beregszaszi, Zsolt Barat <joy@streamminister.de>",
|
|
47 "under developement"
|
|
48 };
|
|
49
|
|
50 LIBAO_EXTERN(alsa)
|
|
51
|
|
52 static snd_pcm_t *alsa_handler;
|
|
53 static snd_pcm_format_t alsa_format;
|
|
54 static snd_pcm_hw_params_t *alsa_hwparams;
|
|
55 static snd_pcm_sw_params_t *alsa_swparams;
|
|
56 static char *alsa_device;
|
|
57
|
|
58 /* possible 4096, original 8192
|
|
59 * was only needed for calculating chunksize? */
|
|
60 static int alsa_fragsize = 4096;
|
|
61 /* 16 sets buffersize to 16 * chunksize is as default 1024
|
|
62 * which seems to be good avarge for most situations
|
|
63 * so buffersize is 16384 frames by default */
|
|
64 static int alsa_fragcount = 16;
|
|
65 static snd_pcm_uframes_t chunk_size = 1024;//is alsa_fragsize / 4
|
|
66
|
|
67 #define MIN_CHUNK_SIZE 1024
|
|
68
|
|
69 static size_t bits_per_sample, bytes_per_sample, bits_per_frame;
|
|
70 static size_t chunk_bytes;
|
|
71
|
|
72 int ao_mmap = 0;
|
|
73 int ao_noblock = 0;
|
|
74 int first = 1;
|
|
75
|
|
76 static int open_mode;
|
|
77 static int set_block_mode;
|
|
78 static int alsa_can_pause = 0;
|
|
79
|
|
80 #define ALSA_DEVICE_SIZE 48
|
|
81
|
|
82 #undef BUFFERTIME
|
|
83 #undef SET_CHUNKSIZE
|
|
84 #undef USE_POLL
|
|
85
|
|
86 /* to set/get/query special features/parameters */
|
|
87 static int control(int cmd, void *arg)
|
|
88 {
|
|
89 switch(cmd) {
|
|
90 case AOCONTROL_QUERY_FORMAT:
|
|
91 return CONTROL_TRUE;
|
|
92 #ifndef WORDS_BIGENDIAN
|
|
93 case AOCONTROL_GET_VOLUME:
|
|
94 case AOCONTROL_SET_VOLUME:
|
|
95 {
|
|
96 ao_control_vol_t *vol = (ao_control_vol_t *)arg;
|
|
97
|
|
98 int err;
|
|
99 snd_mixer_t *handle;
|
|
100 snd_mixer_elem_t *elem;
|
|
101 snd_mixer_selem_id_t *sid;
|
|
102
|
|
103 static char *mix_name = NULL;
|
|
104 static char *card = NULL;
|
|
105
|
|
106 long pmin, pmax;
|
|
107 long get_vol, set_vol;
|
|
108 float calc_vol, diff, f_multi;
|
|
109
|
|
110 if(mix_name == NULL){
|
|
111 if(mixer_device) {
|
|
112 card = strdup(mixer_device);
|
|
113 mix_name = strchr(card, '/');
|
|
114 if(mix_name) {
|
|
115 *mix_name++ = 0;
|
|
116 } else {
|
|
117 mix_name = "PCM";
|
|
118 }
|
|
119 } else {
|
|
120 mix_name = "PCM";
|
|
121 card = "default";
|
|
122 }
|
|
123 }
|
|
124
|
|
125 if(ao_data.format == AFMT_AC3)
|
|
126 return CONTROL_TRUE;
|
|
127
|
|
128 //allocate simple id
|
|
129 snd_mixer_selem_id_alloca(&sid);
|
|
130
|
|
131 //sets simple-mixer index and name
|
|
132 snd_mixer_selem_id_set_index(sid, 0);
|
|
133 snd_mixer_selem_id_set_name(sid, mix_name);
|
|
134
|
|
135 if ((err = snd_mixer_open(&handle, 0)) < 0) {
|
|
136 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: mixer open error: %s\n", snd_strerror(err));
|
|
137 return CONTROL_ERROR;
|
|
138 }
|
|
139
|
|
140 if ((err = snd_mixer_attach(handle, card)) < 0) {
|
|
141 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: mixer attach %s error: %s\n",
|
|
142 card, snd_strerror(err));
|
|
143 snd_mixer_close(handle);
|
|
144 return CONTROL_ERROR;
|
|
145 }
|
|
146
|
|
147 if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
|
|
148 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: mixer register error: %s\n", snd_strerror(err));
|
|
149 snd_mixer_close(handle);
|
|
150 return CONTROL_ERROR;
|
|
151 }
|
|
152 err = snd_mixer_load(handle);
|
|
153 if (err < 0) {
|
|
154 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: mixer load error: %s\n", snd_strerror(err));
|
|
155 snd_mixer_close(handle);
|
|
156 return CONTROL_ERROR;
|
|
157 }
|
|
158
|
|
159 elem = snd_mixer_find_selem(handle, sid);
|
|
160 if (!elem) {
|
|
161 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: unable to find simple control '%s',%i\n",
|
|
162 snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
|
|
163 snd_mixer_close(handle);
|
|
164 return CONTROL_ERROR;
|
|
165 }
|
|
166
|
|
167 snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
|
|
168 f_multi = (100 / (float)pmax);
|
|
169
|
|
170 if (cmd == AOCONTROL_SET_VOLUME) {
|
|
171
|
|
172 diff = (vol->left+vol->right) / 2;
|
|
173 set_vol = rint(diff / f_multi);
|
|
174
|
|
175 if (set_vol < 0)
|
|
176 set_vol = 0;
|
|
177 else if (set_vol > pmax)
|
|
178 set_vol = pmax;
|
|
179
|
|
180 //setting channels
|
|
181 if ((err = snd_mixer_selem_set_playback_volume(elem, 0, set_vol)) < 0) {
|
|
182 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: error setting left channel, %s\n",
|
|
183 snd_strerror(err));
|
|
184 return CONTROL_ERROR;
|
|
185 }
|
|
186 if ((err = snd_mixer_selem_set_playback_volume(elem, 1, set_vol)) < 0) {
|
|
187 mp_msg(MSGT_AO,MSGL_ERR,"alsa-control: error setting right channel, %s\n",
|
|
188 snd_strerror(err));
|
|
189 return CONTROL_ERROR;
|
|
190 }
|
|
191
|
|
192 mp_msg(MSGT_AO,MSGL_DBG2,"diff=%f, set_vol=%li, pmax=%li, mult=%f\n",
|
|
193 diff, set_vol, pmax, f_multi);
|
|
194 }
|
|
195 else {
|
|
196 snd_mixer_selem_get_playback_volume(elem, 0, &get_vol);
|
|
197 calc_vol = get_vol;
|
|
198 calc_vol = rintf(calc_vol * f_multi);
|
|
199
|
|
200 vol->left = vol->right = (int)calc_vol;
|
|
201
|
|
202 mp_msg(MSGT_AO,MSGL_DBG2,"get_vol = %li, calc=%f\n",get_vol, calc_vol);
|
|
203 }
|
|
204 snd_mixer_close(handle);
|
|
205 return CONTROL_OK;
|
|
206 }
|
|
207 #endif
|
|
208
|
|
209 } //end switch
|
|
210 return(CONTROL_UNKNOWN);
|
|
211 }
|
|
212
|
|
213
|
|
214 /*
|
|
215 open & setup audio device
|
|
216 return: 1=success 0=fail
|
|
217 */
|
|
218 static int init(int rate_hz, int channels, int format, int flags)
|
|
219 {
|
|
220 int err;
|
|
221 int cards = -1;
|
|
222 int period_val;
|
|
223 snd_pcm_info_t *alsa_info;
|
|
224 char *str_block_mode;
|
|
225 int device_set = 0;
|
|
226 int dir = 0;
|
|
227 snd_pcm_uframes_t bufsize;
|
|
228
|
|
229 mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz,
|
|
230 channels, audio_out_format_name(format));
|
|
231 alsa_handler = NULL;
|
|
232 mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR);
|
|
233
|
|
234 if ((err = snd_card_next(&cards)) < 0 || cards < 0)
|
|
235 {
|
|
236 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: no soundcards found: %s\n", snd_strerror(err));
|
|
237 return(0);
|
|
238 }
|
|
239
|
|
240 ao_data.samplerate = rate_hz;
|
|
241 ao_data.bps = channels * rate_hz;
|
|
242 ao_data.format = format;
|
|
243 ao_data.channels = channels;
|
|
244 ao_data.outburst = OUTBURST;
|
|
245
|
|
246 switch (format)
|
|
247 {
|
|
248 case AFMT_S8:
|
|
249 alsa_format = SND_PCM_FORMAT_S8;
|
|
250 break;
|
|
251 case AFMT_U8:
|
|
252 alsa_format = SND_PCM_FORMAT_U8;
|
|
253 break;
|
|
254 case AFMT_U16_LE:
|
|
255 alsa_format = SND_PCM_FORMAT_U16_LE;
|
|
256 break;
|
|
257 case AFMT_U16_BE:
|
|
258 alsa_format = SND_PCM_FORMAT_U16_BE;
|
|
259 break;
|
|
260 #ifndef WORDS_BIGENDIAN
|
|
261 case AFMT_AC3:
|
|
262 #endif
|
|
263 case AFMT_S16_LE:
|
|
264 alsa_format = SND_PCM_FORMAT_S16_LE;
|
|
265 break;
|
|
266 #ifdef WORDS_BIGENDIAN
|
|
267 case AFMT_AC3:
|
|
268 #endif
|
|
269 case AFMT_S16_BE:
|
|
270 alsa_format = SND_PCM_FORMAT_S16_BE;
|
|
271 break;
|
|
272 case AFMT_S32_LE:
|
|
273 alsa_format = SND_PCM_FORMAT_S32_LE;
|
|
274 break;
|
|
275 case AFMT_S32_BE:
|
|
276 alsa_format = SND_PCM_FORMAT_S32_BE;
|
|
277 break;
|
12570
|
278 case AFMT_FLOAT:
|
|
279 alsa_format = SND_PCM_FORMAT_FLOAT_LE;
|
|
280 break;
|
12465
|
281
|
|
282 default:
|
|
283 alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1
|
|
284 break;
|
|
285 }
|
|
286
|
|
287 //setting bw according to the input-format. resolution seems to be always s16_le or
|
|
288 //u16_le so 32bit is probably obsolet.
|
|
289 switch(alsa_format)
|
|
290 {
|
12570
|
291 case SND_PCM_FORMAT_S8:
|
|
292 case SND_PCM_FORMAT_U8:
|
|
293 ao_data.bps *= 1;
|
|
294 break;
|
12465
|
295 case SND_PCM_FORMAT_S16_LE:
|
|
296 case SND_PCM_FORMAT_U16_LE:
|
|
297 ao_data.bps *= 2;
|
|
298 break;
|
|
299 case SND_PCM_FORMAT_S32_LE:
|
|
300 case SND_PCM_FORMAT_S32_BE:
|
12570
|
301 case SND_PCM_FORMAT_FLOAT_LE:
|
12465
|
302 ao_data.bps *= 4;
|
|
303 break;
|
|
304 case -1:
|
|
305 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: invalid format (%s) requested - output disabled\n",
|
|
306 audio_out_format_name(format));
|
|
307 return(0);
|
|
308 break;
|
|
309 default:
|
|
310 ao_data.bps *= 2;
|
|
311 mp_msg(MSGT_AO,MSGL_WARN,"alsa-init: couldn't convert to right format. setting bps to: %d", ao_data.bps);
|
|
312 }
|
|
313
|
|
314 if (ao_subdevice) {
|
|
315 //start parsing ao_subdevice, ugly and not thread safe!
|
|
316 //maybe there's a better way?
|
|
317 int i2 = 1;
|
|
318 int i3 = 0;
|
|
319 char *sub_str;
|
|
320
|
|
321 char *token_str[3];
|
|
322 char* test_str = strdup(ao_subdevice);
|
|
323
|
|
324
|
|
325 if ((strcspn(ao_subdevice, ":")) > 0) {
|
|
326
|
|
327 sub_str = strtok(test_str, ":");
|
|
328 *(token_str) = sub_str;
|
|
329
|
|
330 while (((sub_str = strtok(NULL, ":")) != NULL) && (i2 <= 3)) {
|
|
331 *(token_str+i2) = sub_str;
|
|
332 i2 += 1;
|
|
333 }
|
|
334
|
|
335 for (i3=0; i3 <= i2-1; i3++) {
|
|
336 if (strcmp(*(token_str + i3), "mmap") == 0) {
|
|
337 ao_mmap = 1;
|
|
338 }
|
|
339 else if (strcmp(*(token_str+i3), "noblock") == 0) {
|
|
340 ao_noblock = 1;
|
|
341 }
|
|
342 else if (strcmp(*(token_str+i3), "hw") == 0) {
|
|
343 if ((i3 < i2-1) && (strcmp(*(token_str+i3+1), "noblock") != 0) && (strcmp(*(token_str+i3+1), "mmap") != 0)) {
|
|
344 char *tmp;
|
|
345
|
|
346 alsa_device = alloca(ALSA_DEVICE_SIZE);
|
|
347 snprintf(alsa_device, ALSA_DEVICE_SIZE, "hw:%s", *(token_str+(i3+1)));
|
|
348 if ((tmp = strrchr(alsa_device, '.')) && isdigit(*(tmp+1)))
|
|
349 *tmp = ',';
|
|
350 device_set = 1;
|
|
351 }
|
|
352 else {
|
|
353 alsa_device = *(token_str+i3);
|
|
354 device_set = 1;
|
|
355 }
|
|
356 }
|
|
357 else if (device_set == 0 && (!ao_mmap || !ao_noblock)) {
|
|
358 alsa_device = *(token_str+i3);
|
|
359 device_set = 1;
|
|
360 }
|
|
361 }
|
|
362 }
|
|
363 } else { //end parsing ao_subdevice
|
|
364 /* in any case for multichannel playback we should select
|
|
365 * appropriate device
|
|
366 */
|
|
367 char devstr[128];
|
|
368
|
|
369 switch (channels) {
|
|
370 case 1:
|
|
371 case 2:
|
|
372 mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n");
|
|
373 break;
|
|
374 case 4:
|
12570
|
375 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
|
|
376 // hack - use the converter plugin
|
|
377 strcpy(devstr, "plug:surround40");
|
|
378 else
|
|
379 strcpy(devstr, "surround40");
|
12465
|
380 alsa_device = devstr;
|
|
381 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n");
|
|
382 break;
|
|
383 case 6:
|
12570
|
384 if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
|
|
385 strcpy(devstr, "plug:surround51");
|
|
386 else
|
|
387 strcpy(devstr, "surround51");
|
12465
|
388 alsa_device = devstr;
|
|
389 mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n");
|
|
390 break;
|
|
391 default:
|
|
392 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: %d channels are not supported\n",channels);
|
|
393 }
|
|
394 }
|
|
395
|
|
396 /* switch for spdif
|
|
397 * sets opening sequence for SPDIF
|
|
398 * sets also the playback and other switches 'on the fly'
|
|
399 * while opening the abstract alias for the spdif subdevice
|
|
400 * 'iec958'
|
|
401 */
|
|
402 if (format == AFMT_AC3) {
|
|
403 char devstr[128];
|
|
404 unsigned char s[4];
|
|
405 //int err, c; //unused
|
|
406
|
|
407 switch (channels) {
|
|
408 case 1:
|
|
409 case 2:
|
|
410
|
|
411 s[0] = IEC958_AES0_NONAUDIO |
|
|
412 IEC958_AES0_CON_EMPHASIS_NONE;
|
|
413 s[1] = IEC958_AES1_CON_ORIGINAL |
|
|
414 IEC958_AES1_CON_PCM_CODER;
|
|
415 s[2] = 0;
|
|
416 s[3] = IEC958_AES3_CON_FS_48000;
|
|
417
|
|
418 sprintf(devstr, "iec958:AES0=0x%x,AES1=0x%x,AES2=0x%x,AES3=0x%x",
|
|
419 s[0], s[1], s[2], s[3]);
|
|
420
|
|
421 mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3, %i channels\n", channels);
|
|
422 break;
|
|
423 case 4:
|
|
424 strcpy(devstr, "surround40");
|
|
425 break;
|
|
426
|
|
427 case 6:
|
|
428 strcpy(devstr, "surround51");
|
|
429 break;
|
|
430
|
|
431 default:
|
|
432 mp_msg(MSGT_AO,MSGL_ERR,"alsa-spdif-init: %d channels are not supported\n", channels);
|
|
433 }
|
|
434
|
|
435 alsa_device = devstr;
|
|
436 }
|
|
437
|
|
438 if (alsa_device == NULL)
|
|
439 {
|
|
440 int tmp_device, tmp_subdevice, err;
|
|
441
|
|
442 if ((err = snd_pcm_info_malloc(&alsa_info)) < 0)
|
|
443 {
|
|
444 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: memory allocation error: %s\n", snd_strerror(err));
|
|
445 }
|
|
446
|
|
447 if ((alsa_device = alloca(ALSA_DEVICE_SIZE)) == NULL)
|
|
448 {
|
|
449 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: memory allocation error: %s\n", strerror(errno));
|
|
450 }
|
|
451
|
|
452 if ((tmp_device = snd_pcm_info_get_device(alsa_info)) < 0)
|
|
453 {
|
|
454 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: can't get device\n");
|
|
455 }
|
|
456
|
|
457 if ((tmp_subdevice = snd_pcm_info_get_subdevice(alsa_info)) < 0)
|
|
458 {
|
|
459 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: can't get subdevice\n");
|
|
460 }
|
|
461
|
|
462 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: got device=%i, subdevice=%i\n",
|
|
463 tmp_device, tmp_subdevice);
|
|
464
|
|
465 //we are setting here device to default cause it could be configured by the user
|
|
466 //if its not set by the user, it defaults to hw:0,0
|
|
467 if ((err = snprintf(alsa_device, ALSA_DEVICE_SIZE, "default")) <= 0)
|
|
468 {
|
|
469 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: can't write device-id\n");
|
|
470 }
|
|
471
|
|
472 snd_pcm_info_free(alsa_info);
|
|
473 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: %d soundcard%s found, using: %s\n", cards+1,(cards >= 0) ? "" : "s", alsa_device);
|
|
474 } else if (strcmp(alsa_device, "help") == 0) {
|
|
475 printf("alsa-help: available options are:\n");
|
|
476 printf(" mmap: sets mmap-mode\n");
|
|
477 printf(" noblock: sets noblock-mode\n");
|
|
478 printf(" device-name: sets device name (change comma to point)\n");
|
|
479 printf(" example -ao alsa9:mmap:noblock:hw:0.3 sets noblock-mode,\n");
|
|
480 printf(" mmap-mode and the device-name as first card fourth device\n");
|
|
481 return(0);
|
|
482 } else {
|
|
483 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: soundcard set to %s\n", alsa_device);
|
|
484 }
|
|
485
|
|
486 //setting modes for block or nonblock-mode
|
|
487 if (ao_noblock) {
|
|
488 open_mode = SND_PCM_NONBLOCK;
|
|
489 set_block_mode = 1;
|
|
490 str_block_mode = "nonblock-mode";
|
|
491 }
|
|
492 else {
|
|
493 open_mode = 0;
|
|
494 set_block_mode = 0;
|
|
495 str_block_mode = "block-mode";
|
|
496 }
|
|
497
|
|
498 //sets buff/chunksize if its set manually
|
|
499 if (ao_data.buffersize) {
|
|
500 switch (ao_data.buffersize)
|
|
501 {
|
|
502 case 1:
|
|
503 alsa_fragcount = 16;
|
|
504 chunk_size = 512;
|
|
505 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n");
|
|
506 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n");
|
|
507 break;
|
|
508 case 2:
|
|
509 alsa_fragcount = 8;
|
|
510 chunk_size = 1024;
|
|
511 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 8192\n");
|
|
512 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n");
|
|
513 break;
|
|
514 case 3:
|
|
515 alsa_fragcount = 32;
|
|
516 chunk_size = 512;
|
|
517 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n");
|
|
518 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 512\n");
|
|
519 break;
|
|
520 case 4:
|
|
521 alsa_fragcount = 16;
|
|
522 chunk_size = 1024;
|
|
523 mp_msg(MSGT_AO,MSGL_V,"alsa-init: buffersize set manually to 16384\n");
|
|
524 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set manually to 1024\n");
|
|
525 break;
|
|
526 default:
|
|
527 alsa_fragcount = 16;
|
|
528 if (ao_mmap)
|
|
529 chunk_size = 512;
|
|
530 else
|
|
531 chunk_size = 1024;
|
|
532 break;
|
|
533 }
|
|
534 }
|
|
535
|
|
536 if (!alsa_handler) {
|
|
537 //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
|
|
538 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, open_mode)) < 0)
|
|
539 {
|
|
540 if (err != -EBUSY && ao_noblock) {
|
|
541 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: open in nonblock-mode failed, trying to open in block-mode\n");
|
|
542 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
|
543 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: playback open error: %s\n", snd_strerror(err));
|
|
544 return(0);
|
|
545 } else {
|
|
546 set_block_mode = 0;
|
|
547 str_block_mode = "block-mode";
|
|
548 }
|
|
549 } else {
|
|
550 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: playback open error: %s\n", snd_strerror(err));
|
|
551 return(0);
|
|
552 }
|
|
553 }
|
|
554
|
|
555 if ((err = snd_pcm_nonblock(alsa_handler, set_block_mode)) < 0) {
|
|
556 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: error set block-mode %s\n", snd_strerror(err));
|
|
557 } else {
|
|
558 mp_msg(MSGT_AO,MSGL_V,"alsa-init: pcm opend in %s\n", str_block_mode);
|
|
559 }
|
|
560
|
|
561 snd_pcm_hw_params_alloca(&alsa_hwparams);
|
|
562 snd_pcm_sw_params_alloca(&alsa_swparams);
|
|
563
|
|
564 // setting hw-parameters
|
|
565 if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0)
|
|
566 {
|
|
567 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to get initial parameters: %s\n",
|
|
568 snd_strerror(err));
|
|
569 return(0);
|
|
570 }
|
|
571
|
|
572 if (ao_mmap) {
|
|
573 snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof());
|
|
574 snd_pcm_access_mask_none(mask);
|
|
575 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
|
|
576 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
|
|
577 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
|
|
578 err = snd_pcm_hw_params_set_access_mask(alsa_handler, alsa_hwparams, mask);
|
|
579 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: mmap set\n");
|
|
580 } else {
|
|
581 err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
|
|
582 SND_PCM_ACCESS_RW_INTERLEAVED);
|
|
583 }
|
|
584 if (err < 0) {
|
|
585 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set access type: %s\n",
|
|
586 snd_strerror(err));
|
|
587 return (0);
|
|
588 }
|
|
589
|
|
590 /* workaround for nonsupported formats
|
|
591 sets default format to S16_LE if the given formats aren't supported */
|
|
592 if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams,
|
|
593 alsa_format)) < 0)
|
|
594 {
|
|
595 mp_msg(MSGT_AO,MSGL_INFO,
|
|
596 "alsa-init: format %s are not supported by hardware, trying default\n",
|
|
597 audio_out_format_name(format));
|
|
598 alsa_format = SND_PCM_FORMAT_S16_LE;
|
|
599 ao_data.format = AFMT_S16_LE;
|
|
600 ao_data.bps = channels * rate_hz * 2;
|
|
601 }
|
|
602
|
|
603 bytes_per_sample = ao_data.bps / ao_data.samplerate; //it should be here
|
|
604
|
|
605
|
|
606 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
|
|
607 alsa_format)) < 0)
|
|
608 {
|
|
609 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set format: %s\n",
|
|
610 snd_strerror(err));
|
|
611 }
|
|
612
|
|
613 if ((err = snd_pcm_hw_params_set_channels(alsa_handler, alsa_hwparams,
|
|
614 ao_data.channels)) < 0)
|
|
615 {
|
|
616 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set channels: %s\n",
|
|
617 snd_strerror(err));
|
|
618 }
|
|
619
|
|
620 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams,
|
|
621 &ao_data.samplerate, &dir)) < 0)
|
|
622 {
|
|
623 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set samplerate-2: %s\n",
|
|
624 snd_strerror(err));
|
|
625 return(0);
|
|
626 }
|
|
627
|
|
628 #ifdef BUFFERTIME
|
|
629 {
|
|
630 int alsa_buffer_time = 500000; /* original 60 */
|
|
631 int alsa_period_time;
|
|
632 alsa_period_time = alsa_buffer_time/4;
|
|
633 if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams,
|
|
634 &alsa_buffer_time, &dir)) < 0)
|
|
635 {
|
|
636 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set buffer time near: %s\n",
|
|
637 snd_strerror(err));
|
|
638 return(0);
|
|
639 } else
|
|
640 alsa_buffer_time = err;
|
|
641
|
|
642 if ((err = snd_pcm_hw_params_set_period_time_near(alsa_handler, alsa_hwparams,
|
|
643 &alsa_period_time, &dir)) < 0)
|
|
644 /* original: alsa_buffer_time/ao_data.bps */
|
|
645 {
|
|
646 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set period time: %s\n",
|
|
647 snd_strerror(err));
|
|
648 }
|
|
649 mp_msg(MSGT_AO,MSGL_INFO,"alsa-init: buffer_time: %d, period_time :%d\n",
|
|
650 alsa_buffer_time, err);
|
|
651 }
|
|
652 #endif//end SET_BUFFERTIME
|
|
653
|
|
654 #ifdef SET_CHUNKSIZE
|
|
655 {
|
|
656 //set chunksize
|
|
657 dir=0;
|
|
658 if ((err = snd_pcm_hw_params_set_period_size_near(alsa_handler, alsa_hwparams,
|
|
659 &chunk_size, &dir)) < 0)
|
|
660 {
|
|
661 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set periodsize(%d): %s\n",
|
|
662 chunk_size, snd_strerror(err));
|
|
663 }
|
|
664 else {
|
|
665 mp_msg(MSGT_AO,MSGL_V,"alsa-init: chunksize set to %i\n", chunk_size);
|
|
666 }
|
|
667 if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams,
|
|
668 &alsa_fragcount, &dir)) < 0) {
|
|
669 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set periods: %s\n",
|
|
670 snd_strerror(err));
|
|
671 }
|
|
672 else {
|
|
673 mp_msg(MSGT_AO,MSGL_V,"alsa-init: fragcount=%i\n", alsa_fragcount);
|
|
674 }
|
|
675 }
|
|
676 #endif//end SET_CHUNKSIZE
|
|
677
|
|
678 /* finally install hardware parameters */
|
|
679 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
|
|
680 {
|
|
681 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set hw-parameters: %s\n",
|
|
682 snd_strerror(err));
|
|
683 }
|
|
684 // end setting hw-params
|
|
685
|
|
686
|
|
687 // gets buffersize for control
|
|
688 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0)
|
|
689 {
|
|
690 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to get buffersize: %s\n", snd_strerror(err));
|
|
691 }
|
|
692 else {
|
|
693 ao_data.buffersize = bufsize * bytes_per_sample;
|
|
694 mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize);
|
|
695 }
|
|
696
|
|
697 // setting sw-params (only avail-min) if noblocking mode was choosed
|
|
698 if (ao_noblock)
|
|
699 {
|
|
700
|
|
701 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0)
|
|
702 {
|
|
703 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to get parameters: %s\n",
|
|
704 snd_strerror(err));
|
|
705
|
|
706 }
|
|
707
|
|
708 //set min available frames to consider pcm ready (4)
|
|
709 //increased for nonblock-mode should be set dynamically later
|
|
710 if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, 4)) < 0)
|
|
711 {
|
|
712 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to set avail_min %s\n",
|
|
713 snd_strerror(err));
|
|
714 }
|
|
715
|
|
716 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0)
|
|
717 {
|
|
718 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: unable to install sw-params\n");
|
|
719 }
|
|
720
|
|
721 bits_per_sample = snd_pcm_format_physical_width(alsa_format);
|
|
722 bits_per_frame = bits_per_sample * channels;
|
|
723 chunk_bytes = chunk_size * bits_per_frame / 8;
|
|
724
|
|
725 mp_msg(MSGT_AO,MSGL_V,"alsa-init: bits per sample (bps)=%i, bits per frame (bpf)=%i, chunk_bytes=%i\n",bits_per_sample,bits_per_frame,chunk_bytes);}
|
|
726 //end swparams
|
|
727
|
|
728 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
|
|
729 {
|
|
730 mp_msg(MSGT_AO,MSGL_ERR,"alsa-init: pcm prepare error: %s\n", snd_strerror(err));
|
|
731 }
|
|
732
|
|
733 mp_msg(MSGT_AO,MSGL_INFO,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
|
|
734 ao_data.samplerate, ao_data.channels, bytes_per_sample, ao_data.buffersize,
|
|
735 snd_pcm_format_description(alsa_format));
|
|
736
|
|
737 } // end switch alsa_handler (spdif)
|
|
738 alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
|
|
739 return(1);
|
|
740 } // end init
|
|
741
|
|
742
|
|
743 /* close audio device */
|
|
744 static void uninit(int immed)
|
|
745 {
|
|
746
|
|
747 if (alsa_handler) {
|
|
748 int err;
|
|
749
|
|
750 if (!ao_noblock) {
|
|
751 if ((err = snd_pcm_drop(alsa_handler)) < 0)
|
|
752 {
|
|
753 mp_msg(MSGT_AO,MSGL_ERR,"alsa-uninit: pcm drop error: %s\n", snd_strerror(err));
|
|
754 return;
|
|
755 }
|
|
756 }
|
|
757
|
|
758 if ((err = snd_pcm_close(alsa_handler)) < 0)
|
|
759 {
|
|
760 mp_msg(MSGT_AO,MSGL_ERR,"alsa-uninit: pcm close error: %s\n", snd_strerror(err));
|
|
761 return;
|
|
762 }
|
|
763 else {
|
|
764 alsa_handler = NULL;
|
|
765 alsa_device = NULL;
|
|
766 mp_msg(MSGT_AO,MSGL_INFO,"alsa-uninit: pcm closed\n");
|
|
767 }
|
|
768 }
|
|
769 else {
|
|
770 mp_msg(MSGT_AO,MSGL_ERR,"alsa-uninit: no handler defined!\n");
|
|
771 }
|
|
772 }
|
|
773
|
|
774 static void audio_pause()
|
|
775 {
|
|
776 int err;
|
|
777
|
|
778 if (alsa_can_pause) {
|
|
779 if ((err = snd_pcm_pause(alsa_handler, 1)) < 0)
|
|
780 {
|
|
781 mp_msg(MSGT_AO,MSGL_ERR,"alsa-pause: pcm pause error: %s\n", snd_strerror(err));
|
|
782 return;
|
|
783 }
|
|
784 mp_msg(MSGT_AO,MSGL_V,"alsa-pause: pause supported by hardware\n");
|
|
785 } else {
|
|
786 if ((err = snd_pcm_drop(alsa_handler)) < 0)
|
|
787 {
|
|
788 mp_msg(MSGT_AO,MSGL_ERR,"alsa-pause: pcm drop error: %s\n", snd_strerror(err));
|
|
789 return;
|
|
790 }
|
|
791 }
|
|
792 }
|
|
793
|
|
794 static void audio_resume()
|
|
795 {
|
|
796 int err;
|
|
797
|
|
798 if (alsa_can_pause) {
|
|
799 if ((err = snd_pcm_pause(alsa_handler, 0)) < 0)
|
|
800 {
|
|
801 mp_msg(MSGT_AO,MSGL_ERR,"alsa-resume: pcm resume error: %s\n", snd_strerror(err));
|
|
802 return;
|
|
803 }
|
|
804 mp_msg(MSGT_AO,MSGL_V,"alsa-resume: resume supported by hardware\n");
|
|
805 } else {
|
|
806 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
|
|
807 {
|
|
808 mp_msg(MSGT_AO,MSGL_ERR,"alsa-resume: pcm prepare error: %s\n", snd_strerror(err));
|
|
809 return;
|
|
810 }
|
|
811 }
|
|
812 }
|
|
813
|
|
814 /* stop playing and empty buffers (for seeking/pause) */
|
|
815 static void reset()
|
|
816 {
|
|
817 int err;
|
|
818
|
|
819 if ((err = snd_pcm_drop(alsa_handler)) < 0)
|
|
820 {
|
|
821 mp_msg(MSGT_AO,MSGL_ERR,"alsa-reset: pcm drop error: %s\n", snd_strerror(err));
|
|
822 return;
|
|
823 }
|
|
824 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
|
|
825 {
|
|
826 mp_msg(MSGT_AO,MSGL_ERR,"alsa-reset: pcm prepare error: %s\n", snd_strerror(err));
|
|
827 return;
|
|
828 }
|
|
829 return;
|
|
830 }
|
|
831
|
|
832 #ifdef USE_POLL
|
|
833 static int wait_for_poll(snd_pcm_t *handle, struct pollfd *ufds, unsigned int count)
|
|
834 {
|
|
835 unsigned short revents;
|
|
836
|
|
837 while (1) {
|
|
838 poll(ufds, count, -1);
|
|
839 snd_pcm_poll_descriptors_revents(handle, ufds, count, &revents);
|
|
840 if (revents & POLLERR)
|
|
841 return -EIO;
|
|
842 if (revents & POLLOUT)
|
|
843 return 0;
|
|
844 }
|
|
845 }
|
|
846 #endif
|
|
847
|
|
848 #ifndef timersub
|
|
849 #define timersub(a, b, result) \
|
|
850 do { \
|
|
851 (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
|
|
852 (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
|
|
853 if ((result)->tv_usec < 0) { \
|
|
854 --(result)->tv_sec; \
|
|
855 (result)->tv_usec += 1000000; \
|
|
856 } \
|
|
857 } while (0)
|
|
858 #endif
|
|
859
|
|
860 /* I/O error handler */
|
|
861 static int xrun(u_char *str_mode)
|
|
862 {
|
|
863 int err;
|
|
864 snd_pcm_status_t *status;
|
|
865
|
|
866 snd_pcm_status_alloca(&status);
|
|
867
|
|
868 if ((err = snd_pcm_status(alsa_handler, status))<0) {
|
|
869 mp_msg(MSGT_AO,MSGL_ERR,"status error: %s", snd_strerror(err));
|
|
870 return(0);
|
|
871 }
|
|
872
|
|
873 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
|
|
874 struct timeval now, diff, tstamp;
|
|
875 gettimeofday(&now, 0);
|
|
876 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
|
|
877 timersub(&now, &tstamp, &diff);
|
|
878 mp_msg(MSGT_AO,MSGL_INFO,"alsa-%s: xrun of at least %.3f msecs. resetting stream\n",
|
|
879 str_mode,
|
|
880 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
|
|
881 }
|
|
882
|
|
883 if ((err = snd_pcm_prepare(alsa_handler))<0) {
|
|
884 mp_msg(MSGT_AO,MSGL_ERR,"xrun: prepare error: %s", snd_strerror(err));
|
|
885 return(0);
|
|
886 }
|
|
887
|
|
888 return(1); /* ok, data should be accepted again */
|
|
889 }
|
|
890
|
|
891 static int play_normal(void* data, int len);
|
|
892 static int play_mmap(void* data, int len);
|
|
893
|
|
894 static int play(void* data, int len, int flags)
|
|
895 {
|
|
896 int result;
|
|
897 if (ao_mmap)
|
|
898 result = play_mmap(data, len);
|
|
899 else
|
|
900 result = play_normal(data, len);
|
|
901
|
|
902 return result;
|
|
903 }
|
|
904
|
|
905 /*
|
|
906 plays 'len' bytes of 'data'
|
|
907 returns: number of bytes played
|
|
908 modified last at 29.06.02 by jp
|
|
909 thanxs for marius <marius@rospot.com> for giving us the light ;)
|
|
910 */
|
|
911
|
|
912 static int play_normal(void* data, int len)
|
|
913 {
|
|
914
|
|
915 //bytes_per_sample is always 4 for 2 chn S16_LE
|
|
916 int num_frames = len / bytes_per_sample;
|
|
917 char *output_samples = (char *)data;
|
|
918 snd_pcm_sframes_t res = 0;
|
|
919
|
|
920 //mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: frames=%i, len=%i\n",num_frames,len);
|
|
921
|
|
922 if (!alsa_handler) {
|
|
923 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: device configuration error");
|
|
924 return 0;
|
|
925 }
|
|
926
|
|
927 while (num_frames > 0) {
|
|
928
|
|
929 res = snd_pcm_writei(alsa_handler, (void *)output_samples, num_frames);
|
|
930
|
|
931 if (res == -EAGAIN) {
|
|
932 snd_pcm_wait(alsa_handler, 1000);
|
|
933 }
|
|
934 else if (res == -EPIPE) { /* underrun */
|
|
935 if (xrun("play") <= 0) {
|
|
936 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: xrun reset error");
|
|
937 return(0);
|
|
938 }
|
|
939 }
|
|
940 else if (res == -ESTRPIPE) { /* suspend */
|
|
941 mp_msg(MSGT_AO,MSGL_INFO,"alsa-play: pcm in suspend mode. trying to resume\n");
|
|
942 while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN)
|
|
943 sleep(1);
|
|
944 }
|
|
945 else if (res < 0) {
|
|
946 mp_msg(MSGT_AO,MSGL_INFO,"alsa-play: unknown status, trying to reset soundcard\n");
|
|
947 if ((res = snd_pcm_prepare(alsa_handler)) < 0) {
|
|
948 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: snd prepare error");
|
|
949 return(0);
|
|
950 break;
|
|
951 }
|
|
952 }
|
|
953
|
|
954 if (res > 0) {
|
|
955
|
|
956 /* output_samples += ao_data.channels * res; */
|
|
957 output_samples += res * bytes_per_sample;
|
|
958
|
|
959 num_frames -= res;
|
|
960 }
|
|
961
|
|
962 } //end while
|
|
963
|
|
964 if (res < 0) {
|
|
965 mp_msg(MSGT_AO,MSGL_ERR,"alsa-play: write error %s", snd_strerror(res));
|
|
966 return 0;
|
|
967 }
|
|
968 return res < 0 ? (int)res : len - len % bytes_per_sample;
|
|
969 }
|
|
970
|
|
971 /* mmap-mode mainly based on descriptions by Joshua Haberman <joshua@haberman.com>
|
|
972 * 'An overview of the ALSA API' http://people.debian.org/~joshua/x66.html
|
|
973 * and some help by Paul Davis <pbd@op.net> */
|
|
974
|
|
975 static int play_mmap(void* data, int len)
|
|
976 {
|
|
977 snd_pcm_sframes_t commitres, frames_available;
|
|
978 snd_pcm_uframes_t frames_transmit, size, offset;
|
|
979 const snd_pcm_channel_area_t *area;
|
|
980 void *outbuffer;
|
|
981 int err, result;
|
|
982
|
|
983 #ifdef USE_POLL //seems not really be needed
|
|
984 struct pollfd *ufds;
|
|
985 int count;
|
|
986
|
|
987 count = snd_pcm_poll_descriptors_count (alsa_handler);
|
|
988 ufds = malloc(sizeof(struct pollfd) * count);
|
|
989 snd_pcm_poll_descriptors(alsa_handler, ufds, count);
|
|
990
|
|
991 //first wait_for_poll
|
|
992 if (err = (wait_for_poll(alsa_handler, ufds, count) < 0)) {
|
|
993 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_XRUN ||
|
|
994 snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
|
|
995 xrun("play");
|
|
996 }
|
|
997 }
|
|
998 #endif
|
|
999
|
|
1000 outbuffer = alloca(ao_data.buffersize);
|
|
1001
|
|
1002 //don't trust get_space() ;)
|
|
1003 frames_available = snd_pcm_avail_update(alsa_handler) * bytes_per_sample;
|
|
1004 if (frames_available < 0)
|
|
1005 xrun("play");
|
|
1006
|
|
1007 if (frames_available < 4) {
|
|
1008 if (first) {
|
|
1009 first = 0;
|
|
1010 snd_pcm_start(alsa_handler);
|
|
1011 }
|
|
1012 else { //FIXME should break and return 0?
|
|
1013 snd_pcm_wait(alsa_handler, -1);
|
|
1014 first = 1;
|
|
1015 }
|
|
1016 }
|
|
1017
|
|
1018 /* len is simply the available bufferspace got by get_space()
|
|
1019 * but real avail_buffer in frames is ab/bytes_per_sample */
|
|
1020 size = len / bytes_per_sample;
|
|
1021
|
|
1022 //mp_msg(MSGT_AO,MSGL_V,"len: %i size %i, f_avail %i, bps %i ...\n", len, size, frames_available, bytes_per_sample);
|
|
1023
|
|
1024 frames_transmit = size;
|
|
1025
|
|
1026 /* prepare areas and set sw-pointers
|
|
1027 * frames_transmit returns the real available buffer-size
|
|
1028 * sometimes != frames_available cause of ringbuffer 'emulation' */
|
|
1029 snd_pcm_mmap_begin(alsa_handler, &area, &offset, &frames_transmit);
|
|
1030
|
|
1031 /* this is specific to interleaved streams (or non-interleaved
|
|
1032 * streams with only one channel) */
|
|
1033 outbuffer = ((char *) area->addr + (area->first + area->step * offset) / 8); //8
|
|
1034
|
|
1035 //write data
|
|
1036 memcpy(outbuffer, data, (frames_transmit * bytes_per_sample));
|
|
1037
|
|
1038 commitres = snd_pcm_mmap_commit(alsa_handler, offset, frames_transmit);
|
|
1039
|
|
1040 if (commitres < 0 || commitres != frames_transmit) {
|
|
1041 if (snd_pcm_state(alsa_handler) == SND_PCM_STATE_XRUN ||
|
|
1042 snd_pcm_state(alsa_handler) == SND_PCM_STATE_SUSPENDED) {
|
|
1043 xrun("play");
|
|
1044 }
|
|
1045 }
|
|
1046
|
|
1047 //mp_msg(MSGT_AO,MSGL_V,"mmap ft: %i, cres: %i\n", frames_transmit, commitres);
|
|
1048
|
|
1049 /* err = snd_pcm_area_copy(&area, offset, &data, offset, len, alsa_format); */
|
|
1050 /* if (err < 0) { */
|
|
1051 /* mp_msg(MSGT_AO,MSGL_ERR,"area-copy-error\n"); */
|
|
1052 /* return 0; */
|
|
1053 /* } */
|
|
1054
|
|
1055
|
|
1056 //calculate written frames!
|
|
1057 result = commitres * bytes_per_sample;
|
|
1058
|
|
1059
|
|
1060 /* if (verbose) { */
|
|
1061 /* if (len == result) */
|
|
1062 /* mp_msg(MSGT_AO,MSGL_V,"result: %i, frames written: %i ...\n", result, frames_transmit); */
|
|
1063 /* else */
|
|
1064 /* mp_msg(MSGT_AO,MSGL_V,"result: %i, frames written: %i, result != len ...\n", result, frames_transmit); */
|
|
1065 /* } */
|
|
1066
|
|
1067 //mplayer doesn't like -result
|
|
1068 if (result < 0)
|
|
1069 result = 0;
|
|
1070
|
|
1071 #ifdef USE_POLL
|
|
1072 free(ufds);
|
|
1073 #endif
|
|
1074
|
|
1075 return result;
|
|
1076 }
|
|
1077
|
|
1078 /* how many byes are free in the buffer */
|
|
1079 static int get_space()
|
|
1080 {
|
|
1081 snd_pcm_status_t *status;
|
|
1082 int ret;
|
|
1083 char *str_status;
|
|
1084
|
|
1085 //snd_pcm_sframes_t avail_frames = 0;
|
|
1086
|
|
1087 if ((ret = snd_pcm_status_malloc(&status)) < 0)
|
|
1088 {
|
|
1089 mp_msg(MSGT_AO,MSGL_ERR,"alsa-space: memory allocation error: %s\n", snd_strerror(ret));
|
|
1090 return(0);
|
|
1091 }
|
|
1092
|
|
1093 if ((ret = snd_pcm_status(alsa_handler, status)) < 0)
|
|
1094 {
|
|
1095 mp_msg(MSGT_AO,MSGL_ERR,"alsa-space: cannot get pcm status: %s\n", snd_strerror(ret));
|
|
1096 return(0);
|
|
1097 }
|
|
1098
|
|
1099 switch(snd_pcm_status_get_state(status))
|
|
1100 {
|
|
1101 case SND_PCM_STATE_OPEN:
|
|
1102 str_status = "open";
|
|
1103 case SND_PCM_STATE_PREPARED:
|
|
1104 if (str_status != "open") {
|
|
1105 str_status = "prepared";
|
|
1106 first = 1;
|
|
1107 ret = snd_pcm_status_get_avail(status) * bytes_per_sample;
|
|
1108 if (ret == 0) //ugly workaround for hang in mmap-mode
|
|
1109 ret = 10;
|
|
1110 break;
|
|
1111 }
|
|
1112 case SND_PCM_STATE_RUNNING:
|
|
1113 ret = snd_pcm_status_get_avail(status) * bytes_per_sample;
|
|
1114 //avail_frames = snd_pcm_avail_update(alsa_handler) * bytes_per_sample;
|
|
1115 if (str_status != "open" && str_status != "prepared")
|
|
1116 str_status = "running";
|
|
1117 break;
|
|
1118 case SND_PCM_STATE_PAUSED:
|
|
1119 mp_msg(MSGT_AO,MSGL_V,"alsa-space: paused");
|
|
1120 str_status = "paused";
|
|
1121 ret = 0;
|
|
1122 break;
|
|
1123 case SND_PCM_STATE_XRUN:
|
|
1124 xrun("space");
|
|
1125 str_status = "xrun";
|
|
1126 first = 1;
|
|
1127 ret = 0;
|
|
1128 break;
|
|
1129 default:
|
|
1130 str_status = "undefined";
|
|
1131 ret = snd_pcm_status_get_avail(status) * bytes_per_sample;
|
|
1132 if (ret <= 0) {
|
|
1133 xrun("space");
|
|
1134 }
|
|
1135 }
|
|
1136
|
|
1137 if (str_status != "running")
|
|
1138 mp_msg(MSGT_AO,MSGL_V,"alsa-space: free space = %i, status=%i, %s --\n", ret, status, str_status);
|
|
1139 snd_pcm_status_free(status);
|
|
1140
|
|
1141 if (ret < 0) {
|
|
1142 mp_msg(MSGT_AO,MSGL_ERR,"negative value!!\n");
|
|
1143 ret = 0;
|
|
1144 }
|
|
1145
|
|
1146 // workaround for too small value returned
|
|
1147 if (ret < MIN_CHUNK_SIZE)
|
|
1148 ret = 0;
|
|
1149
|
|
1150 return(ret);
|
|
1151 }
|
|
1152
|
|
1153 /* delay in seconds between first and last sample in buffer */
|
|
1154 static float get_delay()
|
|
1155 {
|
|
1156
|
|
1157 if (alsa_handler) {
|
|
1158
|
|
1159 snd_pcm_status_t *status;
|
|
1160 float ret;
|
|
1161
|
|
1162 if ((ret = snd_pcm_status_malloc(&status)) < 0)
|
|
1163 {
|
|
1164 mp_msg(MSGT_AO,MSGL_ERR,"alsa-delay: memory allocation error: %s\n", snd_strerror(ret));
|
|
1165 }
|
|
1166
|
|
1167 if ((ret = snd_pcm_status(alsa_handler, status)) < 0)
|
|
1168 {
|
|
1169 mp_msg(MSGT_AO,MSGL_ERR,"alsa-delay: cannot get pcm status: %s\n", snd_strerror(ret));
|
|
1170 }
|
|
1171
|
|
1172 switch(snd_pcm_status_get_state(status))
|
|
1173 {
|
|
1174 case SND_PCM_STATE_OPEN:
|
|
1175 case SND_PCM_STATE_PREPARED:
|
|
1176 case SND_PCM_STATE_RUNNING:
|
|
1177 ret = (float)snd_pcm_status_get_delay(status)/(float)ao_data.samplerate;
|
|
1178 break;
|
|
1179 default:
|
|
1180 ret = 0;
|
|
1181 }
|
|
1182
|
|
1183 snd_pcm_status_free(status);
|
|
1184
|
|
1185 if (ret < 0)
|
|
1186 ret = 0;
|
|
1187 return(ret);
|
|
1188
|
|
1189 } else {
|
|
1190 return(0);
|
|
1191 }
|
|
1192 }
|