1 /*
2 * MOC - music on console
3 * Copyright (C) 2004 Damian Pietras <daper@daper.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 */
11
12 /* Based on aplay copyright (c) by Jaroslav Kysela <perex@suse.cz> */
13
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17
18 /* _XOPEN_SOURCE is known to break compilation under OpenBSD. */
19 #ifndef OPENBSD
20 # define _XOPEN_SOURCE 500 /* for usleep() */
21 #endif
22
23 #define DEBUG
24
25 #include <stdlib.h>
26 #include <inttypes.h>
27 #include <alsa/asoundlib.h>
28 #include <assert.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <unistd.h>
32
33 #include "common.h"
34 #include "server.h"
35 #include "audio.h"
36 #include "options.h"
37 #include "log.h"
38
39 #define BUFFER_MAX_USEC 300000
40
41 static snd_pcm_t *handle = NULL;
42
43 static struct
44 {
45 unsigned channels;
46 unsigned rate;
47 snd_pcm_format_t format;
48 } params = { 0, 0, SND_PCM_FORMAT_UNKNOWN };
49
50 static int chunk_size = -1; /* in frames */
51 static char alsa_buf[512 * 1024];
52 static int alsa_buf_fill = 0;
53 static int bytes_per_frame;
54
55 static snd_mixer_t *mixer_handle = NULL;
56 static snd_mixer_elem_t *mixer_elem1 = NULL;
57 static snd_mixer_elem_t *mixer_elem2 = NULL;
58 static snd_mixer_elem_t *mixer_elem_curr = NULL;
59 static long mixer1_min = -1, mixer1_max = -1;
60 static long mixer2_min = -1, mixer2_max = -1;
61
62 /* Volume for first and second mixer in range 1-100 despite the actual device
63 * resolution. */
64 static int volume1 = -1;
65 static int volume2 = -1;
66
67 /* Real volume setting as we last read them. */
68 static int real_volume1 = -1;
69 static int real_volume2 = -1;
70
71 /* Scale the mixer value to 0-100 range for first and second channel */
72 #define scale_volume1(v) ((v) - mixer1_min) * 100 / (mixer1_max - mixer1_min)
73 #define scale_volume2(v) ((v) - mixer2_min) * 100 / (mixer2_max - mixer2_min)
74
alsa_shutdown()75 static void alsa_shutdown ()
76 {
77 int err;
78
79 if (mixer_handle && (err = snd_mixer_close(mixer_handle)) < 0)
80 logit ("Can't close mixer: %s", snd_strerror(err));
81 }
82
83 /* Fill caps with the device capabilities. Return 0 on error. */
fill_capabilities(struct output_driver_caps * caps)84 static int fill_capabilities (struct output_driver_caps *caps)
85 {
86 snd_pcm_hw_params_t *hw_params;
87 snd_pcm_format_mask_t *format_mask;
88 int err;
89 unsigned val;
90
91 if ((err = snd_pcm_open(&handle, options_get_str("AlsaDevice"),
92 SND_PCM_STREAM_PLAYBACK,
93 SND_PCM_NONBLOCK)) < 0) {
94 error ("Can't open audio: %s", snd_strerror(err));
95 return 0;
96 }
97
98 if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
99 error ("Can't allocate alsa hardware parameters structure: %s",
100 snd_strerror(err));
101 snd_pcm_close (handle);
102 return 0;
103 }
104
105 if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) {
106 error ("Can't initialize hardware parameters structure: %s",
107 snd_strerror(err));
108 snd_pcm_hw_params_free (hw_params);
109 snd_pcm_close (handle);
110 return 0;
111 }
112
113 if ((err = snd_pcm_hw_params_get_channels_min (hw_params, &val)) < 0) {
114 error ("Can't get the minimum number of channels: %s",
115 snd_strerror(err));
116 snd_pcm_hw_params_free (hw_params);
117 snd_pcm_close (handle);
118 return 0;
119 }
120 caps->min_channels = val;
121
122 if ((err = snd_pcm_hw_params_get_channels_max (hw_params, &val)) < 0) {
123 error ("Can't get the maximum number of channels: %s",
124 snd_strerror(err));
125 snd_pcm_hw_params_free (hw_params);
126 snd_pcm_close (handle);
127 return 0;
128 }
129 caps->max_channels = val;
130
131 if ((err = snd_pcm_format_mask_malloc(&format_mask)) < 0) {
132 error ("Can't allocate format mask: %s", snd_strerror(err));
133 snd_pcm_hw_params_free (hw_params);
134 snd_pcm_close (handle);
135 return 0;
136 }
137 snd_pcm_hw_params_get_format_mask (hw_params, format_mask);
138
139 caps->formats = SFMT_NE;
140 if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_S8))
141 caps->formats |= SFMT_S8;
142 if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_U8))
143 caps->formats |= SFMT_U8;
144 if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_S16))
145 caps->formats |= SFMT_S16;
146 if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_U16))
147 caps->formats |= SFMT_U16;
148 #if 0
149 if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_S24))
150 caps->formats |= SFMT_S32; /* conversion needed */
151 #endif
152 if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_S32))
153 caps->formats |= SFMT_S32;
154 if (snd_pcm_format_mask_test(format_mask, SND_PCM_FORMAT_U32))
155 caps->formats |= SFMT_U32;
156
157 snd_pcm_format_mask_free (format_mask);
158 snd_pcm_hw_params_free (hw_params);
159 snd_pcm_close (handle);
160 handle = NULL;
161
162 return 1;
163 }
164
handle_mixer_events(snd_mixer_t * mixer_handle)165 static void handle_mixer_events (snd_mixer_t *mixer_handle)
166 {
167 int count;
168
169 if ((count = snd_mixer_poll_descriptors_count(mixer_handle)) < 0)
170 logit ("snd_mixer_poll_descriptors_count() failed: %s",
171 snd_strerror(count));
172 else {
173 struct pollfd *fds;
174 int err;
175
176 fds = xcalloc (count, sizeof(struct pollfd));
177
178 if ((err = snd_mixer_poll_descriptors(mixer_handle, fds,
179 count)) < 0)
180 logit ("snd_mixer_poll_descriptors() failed: %s",
181 snd_strerror(err));
182 else {
183 err = poll (fds, count, 0);
184 if (err < 0)
185 error ("poll() failed: %s", strerror(errno));
186 else if (err > 0) {
187 debug ("Mixer event");
188 if ((err = snd_mixer_handle_events(mixer_handle)
189 ) < 0)
190 logit ("snd_mixer_handle_events() failed: %s",
191 snd_strerror(err));
192 }
193
194 }
195
196 free (fds);
197 }
198 }
199
alsa_read_mixer_raw(snd_mixer_elem_t * elem)200 static int alsa_read_mixer_raw (snd_mixer_elem_t *elem)
201 {
202 if (mixer_handle) {
203 long volume = 0;
204 int nchannels = 0;
205 int i;
206 int err;
207
208 assert (elem != NULL);
209
210 handle_mixer_events (mixer_handle);
211
212 for (i = 0; i < SND_MIXER_SCHN_LAST; i++)
213 if (snd_mixer_selem_has_playback_channel (elem, i)) {
214 long vol;
215
216 nchannels++;
217 err = snd_mixer_selem_get_playback_volume (elem, i, &vol);
218 if (err < 0) {
219 error ("Can't read mixer: %s",
220 snd_strerror(err));
221 return -1;
222
223 }
224 /*logit ("Vol %d: %ld", i, vol);*/
225 volume += vol;
226 }
227
228 if (nchannels > 0)
229 volume /= nchannels;
230 else {
231 logit ("Mixer has no channels");
232 volume = -1;
233 }
234
235 /*logit ("Max: %ld, Min: %ld", mixer_max, mixer_min);*/
236 return volume;
237
238 }
239 else
240 return -1;
241 }
242
alsa_init_mixer_channel(const char * name,long * vol_min,long * vol_max)243 static snd_mixer_elem_t *alsa_init_mixer_channel (const char *name,
244 long *vol_min, long *vol_max)
245 {
246 snd_mixer_selem_id_t *sid;
247 snd_mixer_elem_t *elem = NULL;
248
249 snd_mixer_selem_id_malloc (&sid);
250 snd_mixer_selem_id_set_index (sid, 0);
251 snd_mixer_selem_id_set_name (sid, name);
252
253 if (!(elem = snd_mixer_find_selem(mixer_handle, sid)))
254 error ("Can't find mixer %s", name);
255 else if (!snd_mixer_selem_has_playback_volume(elem)) {
256 error ("Mixer device has no playback volume (%s).", name);
257 elem = NULL;
258 }
259 else {
260 snd_mixer_selem_get_playback_volume_range (elem, vol_min,
261 vol_max);
262 logit ("Opened mixer (%s), volume range: %ld-%ld", name,
263 *vol_min, *vol_max);
264 }
265
266 snd_mixer_selem_id_free (sid);
267
268 return elem;
269 }
270
alsa_init(struct output_driver_caps * caps)271 static int alsa_init (struct output_driver_caps *caps)
272 {
273 int err;
274
275 logit ("Initialising ALSA device");
276
277 if ((err = snd_mixer_open(&mixer_handle, 0)) < 0) {
278 error ("Can't open ALSA mixer: %s", snd_strerror(err));
279 mixer_handle = NULL;
280 }
281 else if ((err = snd_mixer_attach(mixer_handle,
282 options_get_str("AlsaDevice"))) < 0) {
283 snd_mixer_close (mixer_handle);
284 mixer_handle = NULL;
285 error ("Can't attach mixer: %s", snd_strerror(err));
286 }
287 else if ((err = snd_mixer_selem_register(mixer_handle, NULL, NULL))
288 < 0) {
289 snd_mixer_close (mixer_handle);
290 mixer_handle = NULL;
291 error ("Can't register mixer: %s", snd_strerror(err));
292 }
293 else if ((err = snd_mixer_load(mixer_handle)) < 0) {
294 snd_mixer_close (mixer_handle);
295 mixer_handle = NULL;
296 error ("Can't load mixer: %s", snd_strerror(err));
297 }
298
299 if (mixer_handle) {
300 mixer_elem1 = alsa_init_mixer_channel (
301 options_get_str ("ALSAMixer1"),
302 &mixer1_min, &mixer1_max);
303 mixer_elem2 = alsa_init_mixer_channel (
304 options_get_str ("ALSAMixer2"),
305 &mixer2_min, &mixer2_max);
306 }
307
308 mixer_elem_curr = mixer_elem1 ? mixer_elem1 : mixer_elem2;
309
310 if (mixer_elem_curr) {
311 if (mixer_elem1 && (real_volume1
312 = alsa_read_mixer_raw(mixer_elem1))
313 != -1)
314 volume1 = scale_volume1 (real_volume1);
315 else {
316 mixer_elem1 = NULL;
317 mixer_elem_curr = mixer_elem2;
318 }
319
320 if (mixer_elem2 && (real_volume2
321 = alsa_read_mixer_raw(mixer_elem2))
322 != -1)
323 volume2 = scale_volume2 (real_volume2);
324 else {
325 mixer_elem2 = NULL;
326 mixer_elem_curr = mixer_elem1;
327 }
328
329 if (!mixer_elem_curr) {
330 snd_mixer_close (mixer_handle);
331 mixer_handle = NULL;
332 }
333 }
334 else if (mixer_handle) {
335 snd_mixer_close (mixer_handle);
336 mixer_handle = NULL;
337 }
338
339 err = fill_capabilities (caps);
340
341 if (err != 0 &&
342 sizeof (long) < 8 && options_was_defaulted ("ALSAStutterDefeat")) {
343 fprintf (stderr,
344 "\n"
345 "Warning: Your system may be vulnerable to stuttering audio.\n"
346 " You should read the example configuration file comments\n"
347 " for the 'ALSAStutterDefeat' option and set it accordingly.\n"
348 " Setting the option will remove this warning.\n"
349 "\n");
350 sleep (5);
351 }
352
353 return err;
354 }
355
alsa_open(struct sound_params * sound_params)356 static int alsa_open (struct sound_params *sound_params)
357 {
358 snd_pcm_hw_params_t *hw_params;
359 int err;
360 unsigned int period_time;
361 unsigned int buffer_time;
362 snd_pcm_uframes_t chunk_frames;
363 snd_pcm_uframes_t buffer_frames;
364 char fmt_name[128];
365
366 switch (sound_params->fmt & SFMT_MASK_FORMAT) {
367 case SFMT_S8:
368 params.format = SND_PCM_FORMAT_S8;
369 break;
370 case SFMT_U8:
371 params.format = SND_PCM_FORMAT_U8;
372 break;
373 case SFMT_S16:
374 params.format = SND_PCM_FORMAT_S16;
375 break;
376 case SFMT_U16:
377 params.format = SND_PCM_FORMAT_U16;
378 break;
379 case SFMT_S32:
380 params.format = SND_PCM_FORMAT_S32;
381 break;
382 case SFMT_U32:
383 params.format = SND_PCM_FORMAT_U32;
384 break;
385 default:
386 error ("Unknown sample format: %s",
387 sfmt_str(sound_params->fmt, fmt_name, sizeof(fmt_name)));
388 params.format = SND_PCM_FORMAT_UNKNOWN;
389 return 0;
390 }
391
392 if ((err = snd_pcm_open(&handle, options_get_str("AlsaDevice"),
393 SND_PCM_STREAM_PLAYBACK,
394 SND_PCM_NONBLOCK)) < 0) {
395 error ("Can't open audio: %s", snd_strerror(err));
396 return 0;
397 }
398
399 if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) {
400 error ("Can't allocate alsa hardware parameters structure: %s",
401 snd_strerror(err));
402 return 0;
403 }
404
405 if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) {
406 error ("Can't initialize hardware parameters structure: %s",
407 snd_strerror(err));
408 snd_pcm_hw_params_free (hw_params);
409 return 0;
410 }
411
412 if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
413 error ("Can't set alsa access type: %s", snd_strerror(err));
414 snd_pcm_hw_params_free (hw_params);
415 return 0;
416 }
417
418 if ((err = snd_pcm_hw_params_set_format (handle, hw_params,
419 params.format)) < 0) {
420 error ("Can't set sample format: %s", snd_strerror(err));
421 snd_pcm_hw_params_free (hw_params);
422 return 0;
423 }
424
425 if (options_get_bool ("ALSAStutterDefeat")) {
426 err = snd_pcm_hw_params_set_rate_resample (handle, hw_params, 0);
427 if (err == 0)
428 logit ("ALSA resampling disabled");
429 else
430 logit ("Unable to disable ALSA resampling: %s", snd_strerror(err));
431 }
432
433 params.rate = sound_params->rate;
434 if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params,
435 ¶ms.rate, 0)) < 0) {
436 error ("Can't set sample rate: %s", snd_strerror(err));
437 snd_pcm_hw_params_free (hw_params);
438 return 0;
439 }
440
441 logit ("Set rate to %u", params.rate);
442
443 if ((err = snd_pcm_hw_params_set_channels (handle, hw_params,
444 sound_params->channels)) < 0) {
445 error ("Can't set number of channels: %s", snd_strerror(err));
446 snd_pcm_hw_params_free (hw_params);
447 return 0;
448 }
449
450 if ((err = snd_pcm_hw_params_get_buffer_time_max(hw_params,
451 &buffer_time, 0)) < 0) {
452 error ("Can't get maximum buffer time: %s", snd_strerror(err));
453 snd_pcm_hw_params_free (hw_params);
454 return 0;
455 }
456
457 if (buffer_time > BUFFER_MAX_USEC)
458 buffer_time = BUFFER_MAX_USEC;
459 period_time = buffer_time / 4;
460
461 if ((err = snd_pcm_hw_params_set_period_time_near(handle, hw_params,
462 &period_time, 0)) < 0) {
463 error ("Can't set period time: %s", snd_strerror(err));
464 snd_pcm_hw_params_free (hw_params);
465 return 0;
466 }
467
468 if ((err = snd_pcm_hw_params_set_buffer_time_near(handle, hw_params,
469 &buffer_time, 0)) < 0) {
470 error ("Can't set buffer time: %s", snd_strerror(err));
471 snd_pcm_hw_params_free (hw_params);
472 return 0;
473 }
474
475 if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) {
476 error ("Can't set audio parameters: %s", snd_strerror(err));
477 snd_pcm_hw_params_free (hw_params);
478 return 0;
479 }
480
481 snd_pcm_hw_params_get_period_size (hw_params, &chunk_frames, 0);
482 snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_frames);
483
484 bytes_per_frame = sound_params->channels
485 * sfmt_Bps(sound_params->fmt);
486
487 logit ("Buffer time: %"PRIu64"us",
488 (uint64_t) buffer_frames * 1000000 / params.rate);
489
490 if (chunk_frames == buffer_frames) {
491 error ("Can't use period equal to buffer size (%lu == %lu)",
492 chunk_frames, buffer_frames);
493 snd_pcm_hw_params_free (hw_params);
494 return 0;
495 }
496
497 chunk_size = chunk_frames * bytes_per_frame;
498
499 debug ("Chunk size: %d", chunk_size);
500
501 snd_pcm_hw_params_free (hw_params);
502
503 if ((err = snd_pcm_prepare(handle)) < 0) {
504 error ("Can't prepare audio interface for use: %s",
505 snd_strerror(err));
506 return 0;
507 }
508
509 logit ("ALSA device opened");
510
511 params.channels = sound_params->channels;
512 alsa_buf_fill = 0;
513 return 1;
514 }
515
516 /* Play from alsa_buf as many chunks as possible. Move the remaining data
517 * to the beginning of the buffer. Return the number of bytes written
518 * or -1 on error. */
play_buf_chunks()519 static int play_buf_chunks ()
520 {
521 int written = 0;
522
523 while (alsa_buf_fill >= chunk_size) {
524 int err;
525
526 err = snd_pcm_writei (handle, alsa_buf + written,
527 chunk_size / bytes_per_frame);
528 if (err == -EAGAIN) {
529 if (snd_pcm_wait(handle, 500) < 0)
530 logit ("snd_pcm_wait() failed");
531 }
532 else if (err == -EPIPE) {
533 logit ("underrun!");
534 if ((err = snd_pcm_prepare(handle)) < 0) {
535 error ("Can't recover after underrun: %s",
536 snd_strerror(err));
537 /* TODO: reopen the device */
538 return -1;
539 }
540 }
541 else if (err == -ESTRPIPE) {
542 logit ("Suspend, trying to resume");
543 while ((err = snd_pcm_resume(handle))
544 == -EAGAIN)
545 sleep (1);
546 if (err < 0) {
547 logit ("Failed, restarting");
548 if ((err = snd_pcm_prepare(handle))
549 < 0) {
550 error ("Failed to restart device: %s",
551 snd_strerror(err));
552 return -1;
553 }
554 }
555 }
556 else if (err < 0) {
557 error ("Can't play: %s", snd_strerror(err));
558 return -1;
559 }
560 else {
561 int written_bytes = err * bytes_per_frame;
562
563 written += written_bytes;
564 alsa_buf_fill -= written_bytes;
565
566 debug ("Played %d bytes", written_bytes);
567 }
568 }
569
570 debug ("%d bytes remain in alsa_buf", alsa_buf_fill);
571 memmove (alsa_buf, alsa_buf + written, alsa_buf_fill);
572
573 return written;
574 }
575
alsa_close()576 static void alsa_close ()
577 {
578 snd_pcm_sframes_t delay;
579
580 assert (handle != NULL);
581
582 /* play what remained in the buffer */
583 if (alsa_buf_fill) {
584 assert (alsa_buf_fill < chunk_size);
585
586 snd_pcm_format_set_silence (params.format,
587 alsa_buf + alsa_buf_fill,
588 (chunk_size - alsa_buf_fill) / bytes_per_frame
589 * params.channels);
590 alsa_buf_fill = chunk_size;
591 play_buf_chunks ();
592 }
593
594 /* Wait for ALSA buffers to empty.
595 * Do not be tempted to use snd_pcm_nonblock() and snd_pcm_drain()
596 * here; there are two bugs in ALSA which make it a bad idea (see
597 * the SVN commit log for r2550). Instead we sleep for the duration
598 * of the still unplayed samples. */
599 if (snd_pcm_delay (handle, &delay) == 0 && delay > 0)
600 usleep ((uint64_t) delay * 1000000 / params.rate);
601 snd_pcm_close (handle);
602 logit ("ALSA device closed");
603
604 params.format = 0;
605 params.rate = 0;
606 params.channels = 0;
607 handle = NULL;
608 }
609
alsa_play(const char * buff,const size_t size)610 static int alsa_play (const char *buff, const size_t size)
611 {
612 int to_write = size;
613 int buf_pos = 0;
614
615 assert (chunk_size > 0);
616
617 debug ("Got %zu bytes to play", size);
618
619 while (to_write) {
620 int to_copy = MIN((size_t)to_write,
621 sizeof(alsa_buf) - (size_t)alsa_buf_fill);
622
623 memcpy (alsa_buf + alsa_buf_fill, buff + buf_pos, to_copy);
624 to_write -= to_copy;
625 buf_pos += to_copy;
626 alsa_buf_fill += to_copy;
627
628 debug ("Copied %d bytes to alsa_buf (now filled with %d bytes)",
629 to_copy, alsa_buf_fill);
630
631 if (play_buf_chunks() < 0)
632 return -1;
633 }
634
635 debug ("Played everything");
636
637 return size;
638 }
639
alsa_read_mixer()640 static int alsa_read_mixer ()
641 {
642 int curr_real_vol = alsa_read_mixer_raw (mixer_elem_curr);
643 int *real_vol;
644 int *vol;
645
646 if (mixer_elem_curr == mixer_elem1) {
647 real_vol = &real_volume1;
648 vol = &volume1;
649 }
650 else {
651 real_vol = &real_volume2;
652 vol = &volume2;
653 }
654
655 if (*real_vol != curr_real_vol) {
656 *real_vol = curr_real_vol;
657 *vol = (vol == &volume1) ? scale_volume1(*real_vol)
658 : scale_volume2(*real_vol);
659 logit ("Mixer volume has changes since we last read it.");
660 }
661
662 return *vol;
663 }
664
alsa_set_mixer(int vol)665 static void alsa_set_mixer (int vol)
666 {
667 if (mixer_handle) {
668 int err;
669 long vol_alsa;
670 long mixer_max, mixer_min;
671 int *real_vol;
672
673 if (mixer_elem_curr == mixer_elem1) {
674 volume1 = vol;
675 mixer_max = mixer1_max;
676 mixer_min = mixer1_min;
677 real_vol = &real_volume1;
678 }
679 else {
680 volume2 = vol;
681 mixer_max = mixer2_max;
682 mixer_min = mixer2_min;
683 real_vol = &real_volume2;
684 }
685
686 vol_alsa = vol * (mixer_max - mixer_min) / 100 + mixer_min;
687
688 debug ("Setting vol to %ld", vol_alsa);
689
690 if ((err = snd_mixer_selem_set_playback_volume_all(
691 mixer_elem_curr, vol_alsa)) < 0)
692 error ("Can't set mixer: %s", snd_strerror(err));
693 else
694 *real_vol = vol_alsa;
695 }
696 }
697
alsa_get_buff_fill()698 static int alsa_get_buff_fill ()
699 {
700 if (handle) {
701 int err;
702 snd_pcm_sframes_t delay;
703
704 if ((err = snd_pcm_delay(handle, &delay)) < 0) {
705 logit ("snd_pcm_delay() failed: %s", snd_strerror(err));
706 return 0;
707 }
708
709 /* delay can be negative when underrun occur */
710 return MAX(delay, 0) * bytes_per_frame;
711 }
712 return 0;
713 }
714
alsa_reset()715 static int alsa_reset ()
716 {
717 if (handle) {
718 int err;
719
720 if ((err = snd_pcm_drop(handle)) < 0) {
721 error ("Can't reset the device: %s", snd_strerror(err));
722 return 0;
723 }
724 if ((err = snd_pcm_prepare(handle)) < 0) {
725 error ("Can't prepare after reset: %s", snd_strerror(err));
726 return 0;
727 }
728
729 alsa_buf_fill = 0;
730 }
731 else
732 logit ("alsa_reset() when the device is not opened.");
733 return 1;
734 }
735
alsa_get_rate()736 static int alsa_get_rate ()
737 {
738 return params.rate;
739 }
740
alsa_toggle_mixer_channel()741 static void alsa_toggle_mixer_channel ()
742 {
743 if (mixer_elem_curr == mixer_elem1 && mixer_elem2)
744 mixer_elem_curr = mixer_elem2;
745 else if (mixer_elem1)
746 mixer_elem_curr = mixer_elem1;
747 }
748
alsa_get_mixer_channel_name()749 static char *alsa_get_mixer_channel_name ()
750 {
751 if (mixer_elem_curr == mixer_elem1)
752 return xstrdup (options_get_str ("ALSAMixer1"));
753 return xstrdup (options_get_str ("ALSAMixer2"));
754 }
755
alsa_funcs(struct hw_funcs * funcs)756 void alsa_funcs (struct hw_funcs *funcs)
757 {
758 funcs->init = alsa_init;
759 funcs->shutdown = alsa_shutdown;
760 funcs->open = alsa_open;
761 funcs->close = alsa_close;
762 funcs->play = alsa_play;
763 funcs->read_mixer = alsa_read_mixer;
764 funcs->set_mixer = alsa_set_mixer;
765 funcs->get_buff_fill = alsa_get_buff_fill;
766 funcs->reset = alsa_reset;
767 funcs->get_rate = alsa_get_rate;
768 funcs->toggle_mixer_channel = alsa_toggle_mixer_channel;
769 funcs->get_mixer_channel_name = alsa_get_mixer_channel_name;
770 }
771