comparison libao2/ao_alsa9.c @ 6633:769246a4eb41

cVS: --------------------------------------------------------------------- added get/set_sound controls stripped down initializing changed play() again outsourced xrun-handling added some cases to get_space() as xrun-handling added nonblock-mode added mmap-mode added subopts for mmap and noblock called mmap and noblock could be accessed as -ao alsa9:noblock:mmap
author joyping
date Wed, 03 Jul 2002 21:43:28 +0000
parents 1595ca898d3b
children df3bf0f971d1
comparison
equal deleted inserted replaced
6632:1c2aa650de79 6633:769246a4eb41
10 */ 10 */
11 11
12 #include <errno.h> 12 #include <errno.h>
13 #include <sys/time.h> 13 #include <sys/time.h>
14 #include <stdlib.h> 14 #include <stdlib.h>
15 //#include <unistd.h> 15 #include <math.h>
16 //#include <string.h> 16 #include <string.h>
17 17
18 #include "../config.h" 18 #include "../config.h"
19 19
20 #if HAVE_SYS_ASOUNDLIB_H 20 #if HAVE_SYS_ASOUNDLIB_H
21 #include <sys/asoundlib.h> 21 #include <sys/asoundlib.h>
46 static snd_pcm_format_t alsa_format; 46 static snd_pcm_format_t alsa_format;
47 static snd_pcm_hw_params_t *alsa_hwparams; 47 static snd_pcm_hw_params_t *alsa_hwparams;
48 static snd_pcm_sw_params_t *alsa_swparams; 48 static snd_pcm_sw_params_t *alsa_swparams;
49 static char *alsa_device; 49 static char *alsa_device;
50 50
51 static int alsa_fragsize = OUTBURST; /* possible 4096, original 8192, OUTBURST is set statically to 512 in config.h but now its not used cause chunksize is allocated dynamically. */ 51 /* possible 4096, original 8192, OUTBURST is set statically to 512 in config.h */
52 static int alsa_fragsize = 4096; //OUTBURST
52 static int alsa_fragcount = 8; 53 static int alsa_fragcount = 8;
53 54
54 static int chunk_size = -1; 55 static int chunk_size = -1;
55 static int buffer_size = 0;
56 static int start_delay = 0;
57 static int stop_delay = 0;
58 static size_t bits_per_sample, bits_per_frame; 56 static size_t bits_per_sample, bits_per_frame;
59 static size_t chunk_bytes; 57 static size_t chunk_bytes;
60 58
59 int ao_mmap = 0;
60 int ao_noblock = 0;
61
62 static int open_mode;
63 static int set_block_mode;
64
61 #define ALSA_DEVICE_SIZE 48 65 #define ALSA_DEVICE_SIZE 48
62 66
63 #define BUFFERTIME /* last undef */ 67 #undef BUFFERTIME
64 #undef SET_PERIOD /* only function now is to set chunksize staticaly, last defined */ 68 #define SET_CHUNKSIZE
65 #define SW_PARAMS /* last undef */
66
67 69
68 snd_pcm_t * 70 snd_pcm_t *
71
69 spdif_init(int acard, int adevice) 72 spdif_init(int acard, int adevice)
70 { 73 {
71 //char *pcm_name = "hw:0,2"; /* first card second device */ 74 //char *pcm_name = "hw:0,2"; /* first card second device */
72 char pcm_name[255]; 75 char pcm_name[255];
73 static snd_aes_iec958_t spdif; 76 static snd_aes_iec958_t spdif;
147 err = snd_pcm_hw_params_any(handler, params); 150 err = snd_pcm_hw_params_any(handler, params);
148 if (err < 0) { 151 if (err < 0) {
149 fprintf(stderr, "Broken configuration for this PCM: no configurations available"); 152 fprintf(stderr, "Broken configuration for this PCM: no configurations available");
150 return NULL; 153 return NULL;
151 } 154 }
152 err = snd_pcm_hw_params_set_access(handler, params, 155
153 SND_PCM_ACCESS_RW_INTERLEAVED); 156 err = snd_pcm_hw_params_set_access(handler, params,SND_PCM_ACCESS_RW_INTERLEAVED);
154 if (err < 0) { 157 if (err < 0) {
155 fprintf(stderr, "Access tyep not available"); 158 fprintf(stderr, "Access tyep not available");
156 return NULL; 159 return NULL;
157 } 160 }
158 err = snd_pcm_hw_params_set_format(handler, params, format); 161 err = snd_pcm_hw_params_set_format(handler, params, format);
184 187
185 188
186 /* to set/get/query special features/parameters */ 189 /* to set/get/query special features/parameters */
187 static int control(int cmd, int arg) 190 static int control(int cmd, int arg)
188 { 191 {
189 return(CONTROL_UNKNOWN); 192 switch(cmd) {
193 case AOCONTROL_QUERY_FORMAT:
194 return CONTROL_TRUE;
195 case AOCONTROL_GET_VOLUME:
196 case AOCONTROL_SET_VOLUME:
197 {
198 ao_control_vol_t *vol = (ao_control_vol_t *)arg;
199
200 int err;
201 snd_mixer_t *handle;
202 snd_mixer_elem_t *elem;
203 snd_mixer_selem_id_t *sid;
204
205 const char *mix_name = "PCM";
206 char *card = "default";
207
208 long pmin, pmax;
209 long get_vol, set_vol;
210 float calc_vol, diff, f_multi;
211
212 if(ao_data.format == AFMT_AC3)
213 return CONTROL_TRUE;
214
215 //allocate simple id
216 snd_mixer_selem_id_alloca(&sid);
217
218 //sets simple-mixer index and name
219 snd_mixer_selem_id_set_index(sid, 0);
220 snd_mixer_selem_id_set_name(sid, mix_name);
221
222 if ((err = snd_mixer_open(&handle, 0)) < 0) {
223 printf("alsa-control: mixer open error: %s\n", snd_strerror(err));
224 return CONTROL_ERROR;
225 }
226
227 if ((err = snd_mixer_attach(handle, card)) < 0) {
228 printf("alsa-control: mixer attach %s error: %s", card, snd_strerror(err));
229 snd_mixer_close(handle);
230 return CONTROL_ERROR;
231 }
232
233 if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) {
234 printf("alsa-control: mixer register error: %s", snd_strerror(err));
235 snd_mixer_close(handle);
236 return CONTROL_ERROR;
237 }
238 err = snd_mixer_load(handle);
239 if (err < 0) {
240 printf("alsa-control: mixer load error: %s", snd_strerror(err));
241 snd_mixer_close(handle);
242 return CONTROL_ERROR;
243 }
244
245 elem = snd_mixer_find_selem(handle, sid);
246 if (!elem) {
247 printf("alsa-control: unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
248 snd_mixer_close(handle);
249 return CONTROL_ERROR;
250 }
251
252 snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
253 f_multi = (100 / (float)pmax);
254
255 if (cmd == AOCONTROL_SET_VOLUME) {
256
257 diff = (vol->left+vol->right) / 2;
258 set_vol = rint(diff / f_multi);
259
260 if (set_vol < 0)
261 set_vol = 0;
262 else if (set_vol > pmax)
263 set_vol = pmax;
264
265 //setting channels
266 if ((err = snd_mixer_selem_set_playback_volume(elem, 0, set_vol)) < 0) {
267 printf("alsa-control: error setting left channel, %s",snd_strerror(err));
268 return CONTROL_ERROR;
269 }
270 if ((err = snd_mixer_selem_set_playback_volume(elem, 1, set_vol)) < 0) {
271 printf("alsa-control: error setting right channel, %s",snd_strerror(err));
272 return CONTROL_ERROR;
273 }
274
275 //printf("diff=%f, set_vol=%i, pmax=%i, mult=%f\n", diff, set_vol, pmax, f_multi);
276 }
277 else {
278 snd_mixer_selem_get_playback_volume(elem, 0, &get_vol);
279 calc_vol = get_vol;
280 calc_vol = rintf(calc_vol * f_multi);
281
282 vol->left = vol->right = (int)calc_vol;
283
284 //printf("get_vol = %i, calc=%i\n",get_vol, calc_vol);
285 }
286 snd_mixer_close(handle);
287 return CONTROL_OK;
288 }
289 }
290 return(CONTROL_UNKNOWN);
190 } 291 }
191 292
192 293
193 /* 294 /*
194 open & setup audio device 295 open & setup audio device
196 */ 297 */
197 static int init(int rate_hz, int channels, int format, int flags) 298 static int init(int rate_hz, int channels, int format, int flags)
198 { 299 {
199 int err; 300 int err;
200 int cards = -1; 301 int cards = -1;
302 int period_val;
201 snd_pcm_info_t *alsa_info; 303 snd_pcm_info_t *alsa_info;
202 304 char *str_block_mode;
203 size_t xfer_align; //new 305
204 snd_pcm_uframes_t start_threshold, stop_threshold; //new
205
206 printf("alsa-init: testing and bugreports are welcome.\n"); 306 printf("alsa-init: testing and bugreports are welcome.\n");
207 printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz, 307 printf("alsa-init: requested format: %d Hz, %d channels, %s\n", rate_hz,
208 channels, audio_out_format_name(format)); 308 channels, audio_out_format_name(format));
209 309
210 alsa_handler = NULL; 310 alsa_handler = NULL;
221 ao_data.samplerate = rate_hz; 321 ao_data.samplerate = rate_hz;
222 ao_data.bps = channels; /* really this is bytes per frame so bad varname */ 322 ao_data.bps = channels; /* really this is bytes per frame so bad varname */
223 ao_data.format = format; 323 ao_data.format = format;
224 ao_data.channels = channels; 324 ao_data.channels = channels;
225 ao_data.outburst = OUTBURST; 325 ao_data.outburst = OUTBURST;
226 ao_data.buffersize = 16384; 326 ao_data.buffersize = MAX_OUTBURST; // was 16384
227 327
228 switch (format) 328 switch (format)
229 { 329 {
230 case AFMT_S8: 330 case AFMT_S8:
231 alsa_format = SND_PCM_FORMAT_S8; 331 alsa_format = SND_PCM_FORMAT_S8;
265 case -1: 365 case -1:
266 printf("alsa-init: invalid format (%s) requested - output disabled\n", 366 printf("alsa-init: invalid format (%s) requested - output disabled\n",
267 audio_out_format_name(format)); 367 audio_out_format_name(format));
268 return(0); 368 return(0);
269 default: 369 default:
270 break; 370 break;
271 } 371 }
272 372
273 if (ao_subdevice != NULL) // ?? makes no sense 373 if (ao_subdevice) {
274 alsa_device = ao_subdevice; 374 //start parsing ao_subdevice, ugly and not thread safe!
375 //maybe there's a better way?
376 int i2 = 1;
377 int i3 = 0;
378 char *sub_str;
379
380 char *token_str[3];
381 char* test_str = strdup(ao_subdevice);
382
383 //printf("subd=%s, test=%s\n", ao_subdevice,test_str);
384
385 if ((strcspn(ao_subdevice, ":")) > 0) {
386
387 sub_str = strtok(test_str, ":");
388 *(token_str) = sub_str;
389
390 while (((sub_str = strtok(NULL, ":")) != NULL) && (i2 <= 3)) {
391 *(token_str+i2) = sub_str;
392 //printf("token %i: %s\n", i2, *(token_str+i2));
393 i2 += 1;
394 }
395
396 for (i3=0; i3 <= i2-1; i3++) {
397 //printf("test %i, %s\n", i3, *(token_str+i3));
398 if (strcmp(*(token_str + i3), "mmap") == 0) {
399 ao_mmap = 1;
400 }
401 else if (strcmp(*(token_str+i3), "noblock") == 0) {
402 ao_noblock = 1;
403 }
404 else if (strcmp(*(token_str+i3), "hw") == 0) {
405 alsa_device = *(token_str+i3);
406 }
407 else if (!alsa_device || !ao_mmap || !ao_noblock) {
408 alsa_device = *(token_str+i3);
409 }
410 }
411 }
412 } //end parsing ao_subdevice
275 413
276 if (alsa_device == NULL) 414 if (alsa_device == NULL)
277 { 415 {
278 int tmp_device, tmp_subdevice, err; 416 int tmp_device, tmp_subdevice, err;
279 417
317 455
318 if (format == AFMT_AC3) { 456 if (format == AFMT_AC3) {
319 // Try to initialize the SPDIF interface 457 // Try to initialize the SPDIF interface
320 alsa_handler = spdif_init(0, 2); 458 alsa_handler = spdif_init(0, 2);
321 } 459 }
322 460
461 //setting modes for block or nonblock-mode
462 if (ao_noblock) {
463 open_mode = SND_PCM_NONBLOCK;
464 set_block_mode = 1;
465 str_block_mode = "nonblock-mode";
466 }
467 else {
468 open_mode = 0;
469 set_block_mode = 0;
470 str_block_mode = "block-mode";
471 }
472
473
474 //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
323 if (!alsa_handler) { 475 if (!alsa_handler) {
324 if ((err = snd_pcm_open(&alsa_handler,alsa_device,SND_PCM_STREAM_PLAYBACK,0)) < 0) 476 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, open_mode)) < 0)
325 { 477 {
326 printf("alsa-init: playback open error: %s\n", snd_strerror(err)); 478 if (ao_noblock) {
327 return(0); 479 printf("alsa-init: open in nonblock-mode failed, trying to open in block-mode\n");
480 if ((err = snd_pcm_open(&alsa_handler, alsa_device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
481 printf("alsa-init: playback open error: %s\n", snd_strerror(err));
482 return(0);
483 } else {
484 set_block_mode = 0;
485 str_block_mode = "block-mode";
328 } 486 }
329 } 487 } else {
488 printf("alsa-init: playback open error: %s\n", snd_strerror(err));
489 return(0);
490 }
491 }
492 }
493
494 if ((err = snd_pcm_nonblock(alsa_handler, set_block_mode)) < 0) {
495 printf("alsa-init: error set block-mode %s\n", snd_strerror(err));
496 }
497 else if (verbose) {
498 printf("alsa-init: pcm opend in %s\n", str_block_mode);
499 }
330 500
331 snd_pcm_hw_params_alloca(&alsa_hwparams); 501 snd_pcm_hw_params_alloca(&alsa_hwparams);
332 snd_pcm_sw_params_alloca(&alsa_swparams); 502 snd_pcm_sw_params_alloca(&alsa_swparams);
333 503
334 // setting hw-parameters 504 // setting hw-parameters
337 printf("alsa-init: unable to get initial parameters: %s\n", 507 printf("alsa-init: unable to get initial parameters: %s\n",
338 snd_strerror(err)); 508 snd_strerror(err));
339 return(0); 509 return(0);
340 } 510 }
341 511
342 if ((err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams, 512 if (ao_mmap) {
343 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) 513 snd_pcm_access_mask_t *mask = alloca(snd_pcm_access_mask_sizeof());
344 { 514 snd_pcm_access_mask_none(mask);
345 printf("alsa-init: unable to set access type: %s\n", 515 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED);
346 snd_strerror(err)); 516 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED);
347 return(0); 517 snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX);
518 err = snd_pcm_hw_params_set_access_mask(alsa_handler, alsa_hwparams, mask);
519 printf("alsa-init: mmap set\n");
520 } else {
521 err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,SND_PCM_ACCESS_RW_INTERLEAVED);
522 printf("alsa-init: interleave set\n");
523 }
524 if (err < 0) {
525 printf("alsa-init: unable to set access type: %s\n", snd_strerror(err));
526 return (0);
348 } 527 }
349 528
350 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams, 529 if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
351 alsa_format)) < 0) 530 alsa_format)) < 0)
352 { 531 {
365 544
366 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, ao_data.samplerate, 0)) < 0) 545 if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams, ao_data.samplerate, 0)) < 0)
367 { 546 {
368 printf("alsa-init: unable to set samplerate-2: %s\n", 547 printf("alsa-init: unable to set samplerate-2: %s\n",
369 snd_strerror(err)); 548 snd_strerror(err));
370 //snd_pcm_hw_params_dump(alsa_hwparams, errlog); jp
371 return(0); 549 return(0);
372 } 550 }
373
374
375 #ifdef SET_PERIOD
376 {
377 if ((err = snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, alsa_fragsize, 0)) < 0)
378 {
379 printf("alsa-init: unable to set periodsize: %s\n", snd_strerror(err));
380 return(0);
381 }
382 }
383 #endif
384 551
385 #ifdef BUFFERTIME 552 #ifdef BUFFERTIME
386 { 553 {
387 int alsa_buffer_time = 500000; /* original 60 */ 554 int alsa_buffer_time = 500000; /* original 60 */
388 555
404 if (verbose) 571 if (verbose)
405 printf("alsa-init: buffer_time: %d, period_time :%d\n",alsa_buffer_time, err); 572 printf("alsa-init: buffer_time: %d, period_time :%d\n",alsa_buffer_time, err);
406 } 573 }
407 #endif 574 #endif
408 575
409 /* get chunk-size */ 576 #ifdef SET_CHUNKSIZE
410 if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, 0)) < 0) 577 {
578 //set chunksize
579 chunk_size = alsa_fragsize / 4;
580
581 if ((err = snd_pcm_hw_params_set_period_size(alsa_handler, alsa_hwparams, chunk_size, 0)) < 0)
411 { 582 {
412 printf("alsa-init: unable to get chunk-size in hw-params: %s\n", snd_strerror(err)); 583 printf("alsa-init: unable to set periodsize: %s\n", snd_strerror(err));
413 return(0); 584 return(0);
414 } else 585 }
415 { 586 else if (verbose) {
416 chunk_size = err; 587 printf("alsa-init: chunksize set to %i\n", chunk_size);
417 if (verbose) {printf("alsa-init: got chunksize %i\n", chunk_size);} 588 }
418 } 589
419 590 //set period_count
420 /* get buffer size */ 591 if ((period_val = snd_pcm_hw_params_get_periods_max(alsa_hwparams, 0)) < alsa_fragcount) {
421 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0) 592 alsa_fragcount = period_val;
422 { 593 }
423 printf("alsa-init: unable to get buffersize in hw-params: %s\n", snd_strerror(err)); 594
424 return(0); 595 if (verbose)
425 } else 596 printf("alsa-init: current val=%i, fragcount=%i\n", period_val, alsa_fragcount);
426 { 597
427 ao_data.buffersize = err; 598 if ((err = snd_pcm_hw_params_set_periods(alsa_handler, alsa_hwparams, alsa_fragcount, 0)) < 0) {
428 if (verbose) {printf("alsa-init: got buffersize %i\n", ao_data.buffersize);} 599 printf("alsa-init: unable to set periods: %s\n", snd_strerror(err));
429 } 600 }
430 601 }
431 if (MAX_OUTBURST > ao_data.buffersize) { //warning if MAX_OUTBURST is bigger than buffersize 602 #endif
432 printf("alsa-init: WARNING! MAX_OUTBURST exceeds your available buffersize.\nalsa-init: MAX_OUTBURST=%i, buffersize=%i\n",MAX_OUTBURST,ao_data.buffersize);}
433
434 if (chunk_size == ao_data.buffersize)
435 {
436 printf("alsa-init: Can't use period equal to buffer size (%u == %lu)", chunk_size, (long)buffer_size);
437 return(0);
438 }
439 603
440 /* finally install hardware parameters */ 604 /* finally install hardware parameters */
441 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0) 605 if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
442 { 606 {
443 printf("alsa-init: unable to set hw-parameters: %s\n", 607 printf("alsa-init: unable to set hw-parameters: %s\n",
444 snd_strerror(err)); 608 snd_strerror(err));
445 return(0); 609 return(0);
446 } 610 }
447 // end setting hw-params 611 // end setting hw-params
448 612
449 #ifdef SW_PARAMS 613
450 { 614 // gets buffersize for control
451 size_t n; 615 if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams)) < 0)
452 xfer_align = snd_pcm_sw_params_get_xfer_align(alsa_swparams); 616 {
453 if (xfer_align == 0) 617 printf("alsa-init: unable to get buffersize: %s\n", snd_strerror(err));
454 xfer_align = 4; 618 return(0);
455 n = (ao_data.buffersize / xfer_align) * xfer_align; 619 }
456 620 else {
457 if (start_delay <= 0) { 621 ao_data.buffersize = err;
458 start_threshold = n + (double) ao_data.samplerate * start_delay / 1000000; 622 if (verbose)
459 } else { 623 printf("alsa-init: got buffersize=%i\n", ao_data.buffersize);
460 start_threshold = (double) ao_data.samplerate * start_delay / 1000000; 624 }
461 } 625
462 if (start_threshold < 1) 626 // setting sw-params (only avail-min) if noblocking mode was choosed
463 start_threshold = 1; 627 if (ao_noblock)
464 if (start_threshold > n) 628 {
465 start_threshold = n;
466
467 if (stop_delay <= 0) {
468 stop_threshold = ao_data.buffersize + (double) ao_data.samplerate * stop_delay / 1000000;
469 } else {
470 stop_threshold = (double) ao_data.samplerate * stop_delay / 1000000;
471 }
472
473 if (verbose) {
474 printf("alsa-init: start_threshold=%lu, stop_threshold=%lu\n",start_threshold,stop_threshold);
475 printf("alsa-init: n=%i\n", n);
476 }
477 629
478 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) 630 if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0)
479 { 631 {
480 printf("alsa-init: unable to get parameters: %s\n",snd_strerror(err)); 632 printf("alsa-init: unable to get parameters: %s\n",snd_strerror(err));
481 return(0); 633 return(0);
482 } 634 }
483 635
484 //set min available frames to consider pcm ready (4) 636 //set min available frames to consider pcm ready (4)
485 if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, 4)) < 0) 637 //increased for nonblock-mode should be set dynamically later
638 if ((err = snd_pcm_sw_params_set_avail_min(alsa_handler, alsa_swparams, chunk_size)) < 0)
486 { 639 {
487 printf("alsa-init: unable to set avail_min %s\n",snd_strerror(err)); 640 printf("alsa-init: unable to set avail_min %s\n",snd_strerror(err));
488 return(0);
489 }
490
491 if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, start_threshold)) < 0)
492 {
493 printf("alsa-init: unable to set start_threshold %s\n",snd_strerror(err));
494 return(0);
495 }
496
497 if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, stop_threshold)) < 0)
498 {
499 printf("alsa-init: unable to set stop_threshold %s\n",snd_strerror(err));
500 return(0);
501 }
502
503 //transfers stream aligned to 4 in nonblocking-mode it would be 1
504 if ((err = snd_pcm_sw_params_set_xfer_align(alsa_handler, alsa_swparams, 4)) < 0)
505 {
506 printf("alsa-init: unable to set xfer_align: %s\n",snd_strerror(err));
507 return(0); 641 return(0);
508 } 642 }
509 643
510 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) 644 if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0)
511 { 645 {
517 bits_per_frame = bits_per_sample * channels; 651 bits_per_frame = bits_per_sample * channels;
518 chunk_bytes = chunk_size * bits_per_frame / 8; 652 chunk_bytes = chunk_size * bits_per_frame / 8;
519 653
520 if (verbose) { 654 if (verbose) {
521 printf("alsa-init: bits per sample (bps)=%i, bits per frame (bpf)=%i, chunk_bytes=%i\n",bits_per_sample,bits_per_frame,chunk_bytes);} 655 printf("alsa-init: bits per sample (bps)=%i, bits per frame (bpf)=%i, chunk_bytes=%i\n",bits_per_sample,bits_per_frame,chunk_bytes);}
522 } 656
523 657 }//end swparams
524 #endif //end swparams
525 658
526 if ((err = snd_pcm_prepare(alsa_handler)) < 0) 659 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
527 { 660 {
528 printf("alsa-init: pcm prepare error: %s\n", snd_strerror(err)); 661 printf("alsa-init: pcm prepare error: %s\n", snd_strerror(err));
529 return(0); 662 return(0);
537 670
538 671
539 /* close audio device */ 672 /* close audio device */
540 static void uninit() 673 static void uninit()
541 { 674 {
675
676 if (alsa_handler) {
542 int err; 677 int err;
543 678
544 //if (alsa_device != NULL) 679 if (!ao_noblock) {
545 //free(alsa_device); 680 if ((err = snd_pcm_drain(alsa_handler)) < 0)
546 681 {
547 //snd_pcm_hw_params_free(alsa_hwparams); 682 printf("alsa-uninit: pcm drain error: %s\n", snd_strerror(err));
548 683 return;
549 if ((err = snd_pcm_drain(alsa_handler)) < 0) 684 }
550 {
551 printf("alsa-uninit: pcm drain error: %s\n", snd_strerror(err));
552 return;
553 } 685 }
554 686
555 if ((err = snd_pcm_close(alsa_handler)) < 0) 687 if ((err = snd_pcm_close(alsa_handler)) < 0)
556 { 688 {
557 printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err)); 689 printf("alsa-uninit: pcm close error: %s\n", snd_strerror(err));
558 return; 690 return;
559 } 691 }
560 else { 692 else {
561 alsa_handler = NULL; 693 alsa_handler = NULL;
562 alsa_device = NULL; 694 alsa_device = NULL;
563 printf("alsa-uninit: pcm closed\n"); 695 printf("alsa-uninit: pcm closed\n");
564 } 696 }
697 }
698 else {
699 printf("alsa-uninit: no handler defined!\n");
700 }
565 } 701 }
566 702
567 static void audio_pause() 703 static void audio_pause()
568 { 704 {
569 int err; 705 int err;
570 706
571 if ((err = snd_pcm_drain(alsa_handler)) < 0) 707 if (!ao_noblock) {
572 { 708 //drain causes error in nonblock-mode!
573 printf("alsa-pause: pcm drain error: %s\n", snd_strerror(err)); 709 if ((err = snd_pcm_drain(alsa_handler)) < 0)
574 return; 710 {
575 } 711 printf("alsa-pause: pcm drain error: %s\n", snd_strerror(err));
576 712 return;
577 #ifdef reset 713 }
578 if ((err = snd_pcm_reset(alsa_handler)) < 0) 714 }
579 { 715 else {
580 printf("alsa-pause: pcm reset error: %s\n", snd_strerror(err)); 716 if (verbose)
581 return; 717 printf("alsa-pause: paused nonblock\n");
582 } 718
583 #endif 719 return;
720 }
584 } 721 }
585 722
586 static void audio_resume() 723 static void audio_resume()
587 { 724 {
588 int err; 725 int err;
597 /* stop playing and empty buffers (for seeking/pause) */ 734 /* stop playing and empty buffers (for seeking/pause) */
598 static void reset() 735 static void reset()
599 { 736 {
600 int err; 737 int err;
601 738
602 if ((err = snd_pcm_drain(alsa_handler)) < 0) 739 if (!ao_noblock) {
603 { 740 //drain causes error in nonblock-mode!
604 printf("alsa-reset: pcm drain error: %s\n", snd_strerror(err)); 741 if ((err = snd_pcm_drain(alsa_handler)) < 0)
605 return; 742 {
606 } 743 printf("alsa-pause: pcm drain error: %s\n", snd_strerror(err));
607 744 return;
608 if ((err = snd_pcm_prepare(alsa_handler)) < 0) 745 }
609 { 746
610 printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err)); 747 if ((err = snd_pcm_prepare(alsa_handler)) < 0)
611 return; 748 {
612 } 749 printf("alsa-reset: pcm prepare error: %s\n", snd_strerror(err));
613 750 return;
751 }
752 } else {
753 if (verbose)
754 printf("alsa-reset: reset nonblocked");
755 return;
756 }
614 } 757 }
615 758
616 #ifndef timersub 759 #ifndef timersub
617 #define timersub(a, b, result) \ 760 #define timersub(a, b, result) \
618 do { \ 761 do { \
623 (result)->tv_usec += 1000000; \ 766 (result)->tv_usec += 1000000; \
624 } \ 767 } \
625 } while (0) 768 } while (0)
626 #endif 769 #endif
627 770
771 /* I/O error handler */
772 static int xrun(u_char *str_mode)
773 {
774 int err;
775 snd_pcm_status_t *status;
776
777 snd_pcm_status_alloca(&status);
778
779 if ((err = snd_pcm_status(alsa_handler, status))<0) {
780 printf("status error: %s", snd_strerror(err));
781 return(0);
782 }
783
784 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
785 struct timeval now, diff, tstamp;
786 gettimeofday(&now, 0);
787 snd_pcm_status_get_trigger_tstamp(status, &tstamp);
788 timersub(&now, &tstamp, &diff);
789 printf("alsa-%s: xrun of at least %.3f msecs. resetting stream\n",
790 str_mode,
791 diff.tv_sec * 1000 + diff.tv_usec / 1000.0);
792 }
793
794 if ((err = snd_pcm_prepare(alsa_handler))<0) {
795 printf("xrun: prepare error: %s", snd_strerror(err));
796 return(0);
797 }
798
799 return(1); /* ok, data should be accepted again */
800 }
801
628 /* 802 /*
629 plays 'len' bytes of 'data' 803 plays 'len' bytes of 'data'
630 returns: number of bytes played 804 returns: number of bytes played
631 modified last at 26.06.02 by jp 805 modified last at 29.06.02 by jp
806 thanxs for marius <marius@rospot.com> for giving us the light ;)
632 */ 807 */
633 808
634 static int play(void* data, int len, int flags) 809 static int play(void* data, int len, int flags)
635 { 810 {
636 811
637 snd_pcm_status_t *status; 812 //ao_data.bps is always 4 cause its set to channels * 2 by alsa_format??
638 813 int num_frames = len / ao_data.bps;
639 int num_frames=len/ao_data.bps;
640 signed short *output_samples=data; 814 signed short *output_samples=data;
641 snd_pcm_sframes_t res = 0; 815 snd_pcm_sframes_t res = 0;
816
817 //printf("alsa-play: frames=%i, len=%i",num_frames,len);
642 818
643 if (!alsa_handler) { 819 if (!alsa_handler) {
644 printf("alsa-play: device configuration error"); 820 printf("alsa-play: device configuration error");
645 return 0; 821 return 0;
646 } 822 }
647 823
648 do { 824 while (num_frames > 0) {
649 if (res == -EPIPE) { /* underrun */ 825
650 snd_pcm_status_alloca(&status); 826 if (ao_mmap) {
651 if ((res = snd_pcm_status(alsa_handler, status))<0) { 827 res = snd_pcm_mmap_writei(alsa_handler, (void *)output_samples, num_frames);
652 printf("alsa-play: buffer underrun. can't determine length");
653 } else { 828 } else {
654 if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) { 829 res = snd_pcm_writei(alsa_handler, (void *)output_samples, num_frames);
655 struct timeval now, diff, tstamp; 830 }
656 gettimeofday(&now, 0); 831
657 snd_pcm_status_get_trigger_tstamp(status, &tstamp); 832 if (res == -EAGAIN) {
658 timersub(&now, &tstamp, &diff); 833 snd_pcm_wait(alsa_handler, 1000);
659 printf("alsa-play: xrun of at least %.3f msecs. resetting stream", 834 }
660 diff.tv_sec * 1000 + diff.tv_usec / 1000.0); 835 else if (res == -EPIPE) { /* underrun */
661 } else 836 if (xrun("play") <= 0) {
662 printf("alsa-play: xrun. can't determine length"); 837 printf("alsa-play: xrun reset error");
663 } 838 return(0);
664 res = snd_pcm_prepare(alsa_handler); 839 }
665 } 840 }
666 else if (res == -ESTRPIPE) { /* suspend */ 841 else if (res == -ESTRPIPE) { /* suspend */
667 printf("alsa-play: pcm in suspend mode. trying to resume"); 842 printf("alsa-play: pcm in suspend mode. trying to resume\n");
668 while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN) 843 while ((res = snd_pcm_resume(alsa_handler)) == -EAGAIN)
669 sleep(1); 844 sleep(1);
670 if (res < 0) 845 }
671 res = snd_pcm_prepare(alsa_handler); 846 else if (res < 0) {
672 } 847 printf("alsa-play: unknown status, trying to reset soundcard\n");
673 848 if ((res = snd_pcm_prepare(alsa_handler)) < 0) {
674 if (res >= 0) 849 printf("alsa-play: snd prepare error");
675 res = snd_pcm_writei(alsa_handler, (void *)output_samples, num_frames); 850 return(0);
676 851 break;
677 if (res > 0) { 852 }
678 output_samples += ao_data.channels * res; 853 }
679 num_frames -= res; 854
680 } 855 if (res > 0) {
681 856 output_samples += ao_data.channels * res;
682 } while (res == -EPIPE || num_frames > 0); 857 num_frames -= res;
858 }
859
860 } //end while
683 861
684 if (res < 0) { 862 if (res < 0) {
685 printf("alsa-play: write error %s", snd_strerror(res)); 863 printf("alsa-play: write error %s", snd_strerror(res));
686 return 0; 864 return 0;
687 } 865 }
688 return res < 0 ? (int)res : len; 866 return res < 0 ? (int)res : len;
689 } 867 }
690 868
691
692 /* how many byes are free in the buffer */ 869 /* how many byes are free in the buffer */
693 static int get_space() 870 static int get_space()
694 { 871 {
695 snd_pcm_status_t *status; 872 snd_pcm_status_t *status;
696 int ret; 873 int ret;
874 char *str_status;
875
876 //snd_pcm_sframes_t avail_frames = 0;
697 877
698 if ((ret = snd_pcm_status_malloc(&status)) < 0) 878 if ((ret = snd_pcm_status_malloc(&status)) < 0)
699 { 879 {
700 printf("alsa-space: memory allocation error: %s\n", snd_strerror(ret)); 880 printf("alsa-space: memory allocation error: %s\n", snd_strerror(ret));
701 return(0); 881 return(0);
707 return(0); 887 return(0);
708 } 888 }
709 889
710 switch(snd_pcm_status_get_state(status)) 890 switch(snd_pcm_status_get_state(status))
711 { 891 {
712 case SND_PCM_STATE_OPEN: 892 case SND_PCM_STATE_OPEN:
713 case SND_PCM_STATE_PREPARED: 893 str_status = "open";
714 case SND_PCM_STATE_RUNNING: 894 case SND_PCM_STATE_PREPARED:
715 ret = snd_pcm_status_get_avail(status) * ao_data.bps; 895 if (str_status != "open")
716 break; 896 str_status = "prepared";
717 default: 897 case SND_PCM_STATE_RUNNING:
718 ret = 0; 898 ret = snd_pcm_status_get_avail(status) * ao_data.bps;
719 } 899 //avail_frames = snd_pcm_avail_update(alsa_handler) * ao_data.bps;
720 900 if (str_status != "open" && str_status != "prepared")
901 str_status = "running";
902 break;
903 case SND_PCM_STATE_PAUSED:
904 if (verbose) printf("alsa-space: paused");
905 str_status = "paused";
906 ret = 0;
907 break;
908 case SND_PCM_STATE_XRUN:
909 xrun("space");
910 str_status = "xrun";
911 ret = 0;
912 break;
913 default:
914 str_status = "undefined";
915 ret = 0;
916 }
917
918 if (verbose && str_status != "running")
919 printf("alsa-space: free space = %i, status=%i, %s --\n", ret, status, str_status);
721 snd_pcm_status_free(status); 920 snd_pcm_status_free(status);
722 921
723 if (ret < 0) 922 if (ret < 0) {
923 printf("negative value!!\n");
724 ret = 0; 924 ret = 0;
725 //printf("alsa-space: free space = %i",ret); 925 }
926
726 return(ret); 927 return(ret);
727 } 928 }
728 929
729 /* delay in seconds between first and last sample in buffer */ 930 /* delay in seconds between first and last sample in buffer */
730 static float get_delay() 931 static float get_delay()
731 { 932 {
933
934 if (alsa_handler) {
935
732 snd_pcm_status_t *status; 936 snd_pcm_status_t *status;
733 float ret; 937 float ret;
734 938
735 if ((ret = snd_pcm_status_malloc(&status)) < 0) 939 if ((ret = snd_pcm_status_malloc(&status)) < 0)
736 { 940 {
758 snd_pcm_status_free(status); 962 snd_pcm_status_free(status);
759 963
760 if (ret < 0) 964 if (ret < 0)
761 ret = 0; 965 ret = 0;
762 return(ret); 966 return(ret);
967
968 } else {
969 return(0);
970 }
763 } 971 }