xref: /openbmc/qemu/audio/alsaaudio.c (revision 06831001)
1 /*
2  * QEMU ALSA audio driver
3  *
4  * Copyright (c) 2005 Vassili Karpov (malc)
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "qemu/osdep.h"
26 #include <alsa/asoundlib.h>
27 #include "qemu/main-loop.h"
28 #include "qemu/module.h"
29 #include "audio.h"
30 #include "trace.h"
31 
32 #pragma GCC diagnostic ignored "-Waddress"
33 
34 #define AUDIO_CAP "alsa"
35 #include "audio_int.h"
36 
37 #define DEBUG_ALSA 0
38 
39 struct pollhlp {
40     snd_pcm_t *handle;
41     struct pollfd *pfds;
42     int count;
43     int mask;
44     AudioState *s;
45 };
46 
47 typedef struct ALSAVoiceOut {
48     HWVoiceOut hw;
49     snd_pcm_t *handle;
50     struct pollhlp pollhlp;
51     Audiodev *dev;
52 } ALSAVoiceOut;
53 
54 typedef struct ALSAVoiceIn {
55     HWVoiceIn hw;
56     snd_pcm_t *handle;
57     struct pollhlp pollhlp;
58     Audiodev *dev;
59 } ALSAVoiceIn;
60 
61 struct alsa_params_req {
62     int freq;
63     snd_pcm_format_t fmt;
64     int nchannels;
65 };
66 
67 struct alsa_params_obt {
68     int freq;
69     AudioFormat fmt;
70     int endianness;
71     int nchannels;
72     snd_pcm_uframes_t samples;
73 };
74 
75 static void G_GNUC_PRINTF (2, 3) alsa_logerr (int err, const char *fmt, ...)
76 {
77     va_list ap;
78 
79     va_start (ap, fmt);
80     AUD_vlog (AUDIO_CAP, fmt, ap);
81     va_end (ap);
82 
83     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
84 }
85 
86 static void G_GNUC_PRINTF (3, 4) alsa_logerr2 (
87     int err,
88     const char *typ,
89     const char *fmt,
90     ...
91     )
92 {
93     va_list ap;
94 
95     AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
96 
97     va_start (ap, fmt);
98     AUD_vlog (AUDIO_CAP, fmt, ap);
99     va_end (ap);
100 
101     AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
102 }
103 
104 static void alsa_fini_poll (struct pollhlp *hlp)
105 {
106     int i;
107     struct pollfd *pfds = hlp->pfds;
108 
109     if (pfds) {
110         for (i = 0; i < hlp->count; ++i) {
111             qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL);
112         }
113         g_free (pfds);
114     }
115     hlp->pfds = NULL;
116     hlp->count = 0;
117     hlp->handle = NULL;
118 }
119 
120 static void alsa_anal_close1 (snd_pcm_t **handlep)
121 {
122     int err = snd_pcm_close (*handlep);
123     if (err) {
124         alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
125     }
126     *handlep = NULL;
127 }
128 
129 static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp)
130 {
131     alsa_fini_poll (hlp);
132     alsa_anal_close1 (handlep);
133 }
134 
135 static int alsa_recover (snd_pcm_t *handle)
136 {
137     int err = snd_pcm_prepare (handle);
138     if (err < 0) {
139         alsa_logerr (err, "Failed to prepare handle %p\n", handle);
140         return -1;
141     }
142     return 0;
143 }
144 
145 static int alsa_resume (snd_pcm_t *handle)
146 {
147     int err = snd_pcm_resume (handle);
148     if (err < 0) {
149         alsa_logerr (err, "Failed to resume handle %p\n", handle);
150         return -1;
151     }
152     return 0;
153 }
154 
155 static void alsa_poll_handler (void *opaque)
156 {
157     int err, count;
158     snd_pcm_state_t state;
159     struct pollhlp *hlp = opaque;
160     unsigned short revents;
161 
162     count = poll (hlp->pfds, hlp->count, 0);
163     if (count < 0) {
164         dolog ("alsa_poll_handler: poll %s\n", strerror (errno));
165         return;
166     }
167 
168     if (!count) {
169         return;
170     }
171 
172     /* XXX: ALSA example uses initial count, not the one returned by
173        poll, correct? */
174     err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds,
175                                             hlp->count, &revents);
176     if (err < 0) {
177         alsa_logerr (err, "snd_pcm_poll_descriptors_revents");
178         return;
179     }
180 
181     if (!(revents & hlp->mask)) {
182         trace_alsa_revents(revents);
183         return;
184     }
185 
186     state = snd_pcm_state (hlp->handle);
187     switch (state) {
188     case SND_PCM_STATE_SETUP:
189         alsa_recover (hlp->handle);
190         break;
191 
192     case SND_PCM_STATE_XRUN:
193         alsa_recover (hlp->handle);
194         break;
195 
196     case SND_PCM_STATE_SUSPENDED:
197         alsa_resume (hlp->handle);
198         break;
199 
200     case SND_PCM_STATE_PREPARED:
201         audio_run(hlp->s, "alsa run (prepared)");
202         break;
203 
204     case SND_PCM_STATE_RUNNING:
205         audio_run(hlp->s, "alsa run (running)");
206         break;
207 
208     default:
209         dolog ("Unexpected state %d\n", state);
210     }
211 }
212 
213 static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask)
214 {
215     int i, count, err;
216     struct pollfd *pfds;
217 
218     count = snd_pcm_poll_descriptors_count (handle);
219     if (count <= 0) {
220         dolog ("Could not initialize poll mode\n"
221                "Invalid number of poll descriptors %d\n", count);
222         return -1;
223     }
224 
225     pfds = g_new0(struct pollfd, count);
226 
227     err = snd_pcm_poll_descriptors (handle, pfds, count);
228     if (err < 0) {
229         alsa_logerr (err, "Could not initialize poll mode\n"
230                      "Could not obtain poll descriptors\n");
231         g_free (pfds);
232         return -1;
233     }
234 
235     for (i = 0; i < count; ++i) {
236         if (pfds[i].events & POLLIN) {
237             qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler, NULL, hlp);
238         }
239         if (pfds[i].events & POLLOUT) {
240             trace_alsa_pollout(i, pfds[i].fd);
241             qemu_set_fd_handler (pfds[i].fd, NULL, alsa_poll_handler, hlp);
242         }
243         trace_alsa_set_handler(pfds[i].events, i, pfds[i].fd, err);
244 
245     }
246     hlp->pfds = pfds;
247     hlp->count = count;
248     hlp->handle = handle;
249     hlp->mask = mask;
250     return 0;
251 }
252 
253 static int alsa_poll_out (HWVoiceOut *hw)
254 {
255     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
256 
257     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT);
258 }
259 
260 static int alsa_poll_in (HWVoiceIn *hw)
261 {
262     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
263 
264     return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN);
265 }
266 
267 static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
268 {
269     switch (fmt) {
270     case AUDIO_FORMAT_S8:
271         return SND_PCM_FORMAT_S8;
272 
273     case AUDIO_FORMAT_U8:
274         return SND_PCM_FORMAT_U8;
275 
276     case AUDIO_FORMAT_S16:
277         if (endianness) {
278             return SND_PCM_FORMAT_S16_BE;
279         } else {
280             return SND_PCM_FORMAT_S16_LE;
281         }
282 
283     case AUDIO_FORMAT_U16:
284         if (endianness) {
285             return SND_PCM_FORMAT_U16_BE;
286         } else {
287             return SND_PCM_FORMAT_U16_LE;
288         }
289 
290     case AUDIO_FORMAT_S32:
291         if (endianness) {
292             return SND_PCM_FORMAT_S32_BE;
293         } else {
294             return SND_PCM_FORMAT_S32_LE;
295         }
296 
297     case AUDIO_FORMAT_U32:
298         if (endianness) {
299             return SND_PCM_FORMAT_U32_BE;
300         } else {
301             return SND_PCM_FORMAT_U32_LE;
302         }
303 
304     case AUDIO_FORMAT_F32:
305         if (endianness) {
306             return SND_PCM_FORMAT_FLOAT_BE;
307         } else {
308             return SND_PCM_FORMAT_FLOAT_LE;
309         }
310 
311     default:
312         dolog ("Internal logic error: Bad audio format %d\n", fmt);
313 #ifdef DEBUG_AUDIO
314         abort ();
315 #endif
316         return SND_PCM_FORMAT_U8;
317     }
318 }
319 
320 static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
321                            int *endianness)
322 {
323     switch (alsafmt) {
324     case SND_PCM_FORMAT_S8:
325         *endianness = 0;
326         *fmt = AUDIO_FORMAT_S8;
327         break;
328 
329     case SND_PCM_FORMAT_U8:
330         *endianness = 0;
331         *fmt = AUDIO_FORMAT_U8;
332         break;
333 
334     case SND_PCM_FORMAT_S16_LE:
335         *endianness = 0;
336         *fmt = AUDIO_FORMAT_S16;
337         break;
338 
339     case SND_PCM_FORMAT_U16_LE:
340         *endianness = 0;
341         *fmt = AUDIO_FORMAT_U16;
342         break;
343 
344     case SND_PCM_FORMAT_S16_BE:
345         *endianness = 1;
346         *fmt = AUDIO_FORMAT_S16;
347         break;
348 
349     case SND_PCM_FORMAT_U16_BE:
350         *endianness = 1;
351         *fmt = AUDIO_FORMAT_U16;
352         break;
353 
354     case SND_PCM_FORMAT_S32_LE:
355         *endianness = 0;
356         *fmt = AUDIO_FORMAT_S32;
357         break;
358 
359     case SND_PCM_FORMAT_U32_LE:
360         *endianness = 0;
361         *fmt = AUDIO_FORMAT_U32;
362         break;
363 
364     case SND_PCM_FORMAT_S32_BE:
365         *endianness = 1;
366         *fmt = AUDIO_FORMAT_S32;
367         break;
368 
369     case SND_PCM_FORMAT_U32_BE:
370         *endianness = 1;
371         *fmt = AUDIO_FORMAT_U32;
372         break;
373 
374     case SND_PCM_FORMAT_FLOAT_LE:
375         *endianness = 0;
376         *fmt = AUDIO_FORMAT_F32;
377         break;
378 
379     case SND_PCM_FORMAT_FLOAT_BE:
380         *endianness = 1;
381         *fmt = AUDIO_FORMAT_F32;
382         break;
383 
384     default:
385         dolog ("Unrecognized audio format %d\n", alsafmt);
386         return -1;
387     }
388 
389     return 0;
390 }
391 
392 static void alsa_dump_info (struct alsa_params_req *req,
393                             struct alsa_params_obt *obt,
394                             snd_pcm_format_t obtfmt,
395                             AudiodevAlsaPerDirectionOptions *apdo)
396 {
397     dolog("parameter | requested value | obtained value\n");
398     dolog("format    |      %10d |     %10d\n", req->fmt, obtfmt);
399     dolog("channels  |      %10d |     %10d\n",
400           req->nchannels, obt->nchannels);
401     dolog("frequency |      %10d |     %10d\n", req->freq, obt->freq);
402     dolog("============================================\n");
403     dolog("requested: buffer len %" PRId32 " period len %" PRId32 "\n",
404           apdo->buffer_length, apdo->period_length);
405     dolog("obtained: samples %ld\n", obt->samples);
406 }
407 
408 static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
409 {
410     int err;
411     snd_pcm_sw_params_t *sw_params;
412 
413     snd_pcm_sw_params_alloca (&sw_params);
414 
415     err = snd_pcm_sw_params_current (handle, sw_params);
416     if (err < 0) {
417         dolog ("Could not fully initialize DAC\n");
418         alsa_logerr (err, "Failed to get current software parameters\n");
419         return;
420     }
421 
422     err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
423     if (err < 0) {
424         dolog ("Could not fully initialize DAC\n");
425         alsa_logerr (err, "Failed to set software threshold to %ld\n",
426                      threshold);
427         return;
428     }
429 
430     err = snd_pcm_sw_params (handle, sw_params);
431     if (err < 0) {
432         dolog ("Could not fully initialize DAC\n");
433         alsa_logerr (err, "Failed to set software parameters\n");
434         return;
435     }
436 }
437 
438 static int alsa_open(bool in, struct alsa_params_req *req,
439                      struct alsa_params_obt *obt, snd_pcm_t **handlep,
440                      Audiodev *dev)
441 {
442     AudiodevAlsaOptions *aopts = &dev->u.alsa;
443     AudiodevAlsaPerDirectionOptions *apdo = in ? aopts->in : aopts->out;
444     snd_pcm_t *handle;
445     snd_pcm_hw_params_t *hw_params;
446     int err;
447     unsigned int freq, nchannels;
448     const char *pcm_name = apdo->dev ?: "default";
449     snd_pcm_uframes_t obt_buffer_size;
450     const char *typ = in ? "ADC" : "DAC";
451     snd_pcm_format_t obtfmt;
452 
453     freq = req->freq;
454     nchannels = req->nchannels;
455 
456     snd_pcm_hw_params_alloca (&hw_params);
457 
458     err = snd_pcm_open (
459         &handle,
460         pcm_name,
461         in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
462         SND_PCM_NONBLOCK
463         );
464     if (err < 0) {
465         alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name);
466         return -1;
467     }
468 
469     err = snd_pcm_hw_params_any (handle, hw_params);
470     if (err < 0) {
471         alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
472         goto err;
473     }
474 
475     err = snd_pcm_hw_params_set_access (
476         handle,
477         hw_params,
478         SND_PCM_ACCESS_RW_INTERLEAVED
479         );
480     if (err < 0) {
481         alsa_logerr2 (err, typ, "Failed to set access type\n");
482         goto err;
483     }
484 
485     err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
486     if (err < 0) {
487         alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
488     }
489 
490     err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
491     if (err < 0) {
492         alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
493         goto err;
494     }
495 
496     err = snd_pcm_hw_params_set_channels_near (
497         handle,
498         hw_params,
499         &nchannels
500         );
501     if (err < 0) {
502         alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
503                       req->nchannels);
504         goto err;
505     }
506 
507     if (apdo->buffer_length) {
508         int dir = 0;
509         unsigned int btime = apdo->buffer_length;
510 
511         err = snd_pcm_hw_params_set_buffer_time_near(
512             handle, hw_params, &btime, &dir);
513 
514         if (err < 0) {
515             alsa_logerr2(err, typ, "Failed to set buffer time to %" PRId32 "\n",
516                          apdo->buffer_length);
517             goto err;
518         }
519 
520         if (apdo->has_buffer_length && btime != apdo->buffer_length) {
521             dolog("Requested buffer time %" PRId32
522                   " was rejected, using %u\n", apdo->buffer_length, btime);
523         }
524     }
525 
526     if (apdo->period_length) {
527         int dir = 0;
528         unsigned int ptime = apdo->period_length;
529 
530         err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &ptime,
531                                                      &dir);
532 
533         if (err < 0) {
534             alsa_logerr2(err, typ, "Failed to set period time to %" PRId32 "\n",
535                          apdo->period_length);
536             goto err;
537         }
538 
539         if (apdo->has_period_length && ptime != apdo->period_length) {
540             dolog("Requested period time %" PRId32 " was rejected, using %d\n",
541                   apdo->period_length, ptime);
542         }
543     }
544 
545     err = snd_pcm_hw_params (handle, hw_params);
546     if (err < 0) {
547         alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
548         goto err;
549     }
550 
551     err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
552     if (err < 0) {
553         alsa_logerr2 (err, typ, "Failed to get buffer size\n");
554         goto err;
555     }
556 
557     err = snd_pcm_hw_params_get_format (hw_params, &obtfmt);
558     if (err < 0) {
559         alsa_logerr2 (err, typ, "Failed to get format\n");
560         goto err;
561     }
562 
563     if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) {
564         dolog ("Invalid format was returned %d\n", obtfmt);
565         goto err;
566     }
567 
568     err = snd_pcm_prepare (handle);
569     if (err < 0) {
570         alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
571         goto err;
572     }
573 
574     if (!in && aopts->has_threshold && aopts->threshold) {
575         struct audsettings as = { .freq = freq };
576         alsa_set_threshold(
577             handle,
578             audio_buffer_frames(qapi_AudiodevAlsaPerDirectionOptions_base(apdo),
579                                 &as, aopts->threshold));
580     }
581 
582     obt->nchannels = nchannels;
583     obt->freq = freq;
584     obt->samples = obt_buffer_size;
585 
586     *handlep = handle;
587 
588     if (DEBUG_ALSA || obtfmt != req->fmt ||
589         obt->nchannels != req->nchannels || obt->freq != req->freq) {
590         dolog ("Audio parameters for %s\n", typ);
591         alsa_dump_info(req, obt, obtfmt, apdo);
592     }
593 
594     return 0;
595 
596  err:
597     alsa_anal_close1 (&handle);
598     return -1;
599 }
600 
601 static size_t alsa_buffer_get_free(HWVoiceOut *hw)
602 {
603     ALSAVoiceOut *alsa = (ALSAVoiceOut *)hw;
604     snd_pcm_sframes_t avail;
605     size_t alsa_free, generic_free, generic_in_use;
606 
607     avail = snd_pcm_avail_update(alsa->handle);
608     if (avail < 0) {
609         if (avail == -EPIPE) {
610             if (!alsa_recover(alsa->handle)) {
611                 avail = snd_pcm_avail_update(alsa->handle);
612             }
613         }
614         if (avail < 0) {
615             alsa_logerr(avail,
616                         "Could not obtain number of available frames\n");
617             avail = 0;
618         }
619     }
620 
621     alsa_free = avail * hw->info.bytes_per_frame;
622     generic_free = audio_generic_buffer_get_free(hw);
623     generic_in_use = hw->samples * hw->info.bytes_per_frame - generic_free;
624     if (generic_in_use) {
625         /*
626          * This code can only be reached in the unlikely case that
627          * snd_pcm_avail_update() returned a larger number of frames
628          * than snd_pcm_writei() could write. Make sure that all
629          * remaining bytes in the generic buffer can be written.
630          */
631         alsa_free = alsa_free > generic_in_use ? alsa_free - generic_in_use : 0;
632     }
633 
634     return alsa_free;
635 }
636 
637 static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
638 {
639     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
640     size_t pos = 0;
641     size_t len_frames = len / hw->info.bytes_per_frame;
642 
643     while (len_frames) {
644         char *src = advance(buf, pos);
645         snd_pcm_sframes_t written;
646 
647         written = snd_pcm_writei(alsa->handle, src, len_frames);
648 
649         if (written <= 0) {
650             switch (written) {
651             case 0:
652                 trace_alsa_wrote_zero(len_frames);
653                 return pos;
654 
655             case -EPIPE:
656                 if (alsa_recover(alsa->handle)) {
657                     alsa_logerr(written, "Failed to write %zu frames\n",
658                                 len_frames);
659                     return pos;
660                 }
661                 trace_alsa_xrun_out();
662                 continue;
663 
664             case -ESTRPIPE:
665                 /*
666                  * stream is suspended and waiting for an application
667                  * recovery
668                  */
669                 if (alsa_resume(alsa->handle)) {
670                     alsa_logerr(written, "Failed to write %zu frames\n",
671                                 len_frames);
672                     return pos;
673                 }
674                 trace_alsa_resume_out();
675                 continue;
676 
677             case -EAGAIN:
678                 return pos;
679 
680             default:
681                 alsa_logerr(written, "Failed to write %zu frames from %p\n",
682                             len, src);
683                 return pos;
684             }
685         }
686 
687         pos += written * hw->info.bytes_per_frame;
688         if (written < len_frames) {
689             break;
690         }
691         len_frames -= written;
692     }
693 
694     return pos;
695 }
696 
697 static void alsa_fini_out (HWVoiceOut *hw)
698 {
699     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
700 
701     ldebug ("alsa_fini\n");
702     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
703 }
704 
705 static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as,
706                          void *drv_opaque)
707 {
708     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
709     struct alsa_params_req req;
710     struct alsa_params_obt obt;
711     snd_pcm_t *handle;
712     struct audsettings obt_as;
713     Audiodev *dev = drv_opaque;
714 
715     req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
716     req.freq = as->freq;
717     req.nchannels = as->nchannels;
718 
719     if (alsa_open(0, &req, &obt, &handle, dev)) {
720         return -1;
721     }
722 
723     obt_as.freq = obt.freq;
724     obt_as.nchannels = obt.nchannels;
725     obt_as.fmt = obt.fmt;
726     obt_as.endianness = obt.endianness;
727 
728     audio_pcm_init_info (&hw->info, &obt_as);
729     hw->samples = obt.samples;
730 
731     alsa->pollhlp.s = hw->s;
732     alsa->handle = handle;
733     alsa->dev = dev;
734     return 0;
735 }
736 
737 #define VOICE_CTL_PAUSE 0
738 #define VOICE_CTL_PREPARE 1
739 #define VOICE_CTL_START 2
740 
741 static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
742 {
743     int err;
744 
745     if (ctl == VOICE_CTL_PAUSE) {
746         err = snd_pcm_drop (handle);
747         if (err < 0) {
748             alsa_logerr (err, "Could not stop %s\n", typ);
749             return -1;
750         }
751     } else {
752         err = snd_pcm_prepare (handle);
753         if (err < 0) {
754             alsa_logerr (err, "Could not prepare handle for %s\n", typ);
755             return -1;
756         }
757         if (ctl == VOICE_CTL_START) {
758             err = snd_pcm_start(handle);
759             if (err < 0) {
760                 alsa_logerr (err, "Could not start handle for %s\n", typ);
761                 return -1;
762             }
763         }
764     }
765 
766     return 0;
767 }
768 
769 static void alsa_enable_out(HWVoiceOut *hw, bool enable)
770 {
771     ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
772     AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.out;
773 
774     if (enable) {
775         bool poll_mode = apdo->try_poll;
776 
777         ldebug("enabling voice\n");
778         if (poll_mode && alsa_poll_out(hw)) {
779             poll_mode = 0;
780         }
781         hw->poll_mode = poll_mode;
782         alsa_voice_ctl(alsa->handle, "playback", VOICE_CTL_PREPARE);
783     } else {
784         ldebug("disabling voice\n");
785         if (hw->poll_mode) {
786             hw->poll_mode = 0;
787             alsa_fini_poll(&alsa->pollhlp);
788         }
789         alsa_voice_ctl(alsa->handle, "playback", VOICE_CTL_PAUSE);
790     }
791 }
792 
793 static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
794 {
795     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
796     struct alsa_params_req req;
797     struct alsa_params_obt obt;
798     snd_pcm_t *handle;
799     struct audsettings obt_as;
800     Audiodev *dev = drv_opaque;
801 
802     req.fmt = aud_to_alsafmt (as->fmt, as->endianness);
803     req.freq = as->freq;
804     req.nchannels = as->nchannels;
805 
806     if (alsa_open(1, &req, &obt, &handle, dev)) {
807         return -1;
808     }
809 
810     obt_as.freq = obt.freq;
811     obt_as.nchannels = obt.nchannels;
812     obt_as.fmt = obt.fmt;
813     obt_as.endianness = obt.endianness;
814 
815     audio_pcm_init_info (&hw->info, &obt_as);
816     hw->samples = obt.samples;
817 
818     alsa->pollhlp.s = hw->s;
819     alsa->handle = handle;
820     alsa->dev = dev;
821     return 0;
822 }
823 
824 static void alsa_fini_in (HWVoiceIn *hw)
825 {
826     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
827 
828     alsa_anal_close (&alsa->handle, &alsa->pollhlp);
829 }
830 
831 static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len)
832 {
833     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
834     size_t pos = 0;
835 
836     while (len) {
837         void *dst = advance(buf, pos);
838         snd_pcm_sframes_t nread;
839 
840         nread = snd_pcm_readi(
841             alsa->handle, dst, len / hw->info.bytes_per_frame);
842 
843         if (nread <= 0) {
844             switch (nread) {
845             case 0:
846                 trace_alsa_read_zero(len);
847                 return pos;
848 
849             case -EPIPE:
850                 if (alsa_recover(alsa->handle)) {
851                     alsa_logerr(nread, "Failed to read %zu frames\n", len);
852                     return pos;
853                 }
854                 trace_alsa_xrun_in();
855                 continue;
856 
857             case -EAGAIN:
858                 return pos;
859 
860             default:
861                 alsa_logerr(nread, "Failed to read %zu frames to %p\n",
862                             len, dst);
863                 return pos;
864             }
865         }
866 
867         pos += nread * hw->info.bytes_per_frame;
868         len -= nread * hw->info.bytes_per_frame;
869     }
870 
871     return pos;
872 }
873 
874 static void alsa_enable_in(HWVoiceIn *hw, bool enable)
875 {
876     ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
877     AudiodevAlsaPerDirectionOptions *apdo = alsa->dev->u.alsa.in;
878 
879     if (enable) {
880         bool poll_mode = apdo->try_poll;
881 
882         ldebug("enabling voice\n");
883         if (poll_mode && alsa_poll_in(hw)) {
884             poll_mode = 0;
885         }
886         hw->poll_mode = poll_mode;
887 
888         alsa_voice_ctl(alsa->handle, "capture", VOICE_CTL_START);
889     } else {
890         ldebug ("disabling voice\n");
891         if (hw->poll_mode) {
892             hw->poll_mode = 0;
893             alsa_fini_poll(&alsa->pollhlp);
894         }
895         alsa_voice_ctl(alsa->handle, "capture", VOICE_CTL_PAUSE);
896     }
897 }
898 
899 static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo)
900 {
901     if (!apdo->has_try_poll) {
902         apdo->try_poll = true;
903         apdo->has_try_poll = true;
904     }
905 }
906 
907 static void *alsa_audio_init(Audiodev *dev)
908 {
909     AudiodevAlsaOptions *aopts;
910     assert(dev->driver == AUDIODEV_DRIVER_ALSA);
911 
912     aopts = &dev->u.alsa;
913     alsa_init_per_direction(aopts->in);
914     alsa_init_per_direction(aopts->out);
915 
916     /* don't set has_* so alsa_open can identify it wasn't set by the user */
917     if (!dev->u.alsa.out->has_period_length) {
918         /* 256 frames assuming 44100Hz */
919         dev->u.alsa.out->period_length = 5805;
920     }
921     if (!dev->u.alsa.out->has_buffer_length) {
922         /* 4096 frames assuming 44100Hz */
923         dev->u.alsa.out->buffer_length = 92880;
924     }
925 
926     if (!dev->u.alsa.in->has_period_length) {
927         /* 256 frames assuming 44100Hz */
928         dev->u.alsa.in->period_length = 5805;
929     }
930     if (!dev->u.alsa.in->has_buffer_length) {
931         /* 4096 frames assuming 44100Hz */
932         dev->u.alsa.in->buffer_length = 92880;
933     }
934 
935     return dev;
936 }
937 
938 static void alsa_audio_fini (void *opaque)
939 {
940 }
941 
942 static struct audio_pcm_ops alsa_pcm_ops = {
943     .init_out = alsa_init_out,
944     .fini_out = alsa_fini_out,
945     .write    = alsa_write,
946     .buffer_get_free = alsa_buffer_get_free,
947     .run_buffer_out = audio_generic_run_buffer_out,
948     .enable_out = alsa_enable_out,
949 
950     .init_in  = alsa_init_in,
951     .fini_in  = alsa_fini_in,
952     .read     = alsa_read,
953     .run_buffer_in = audio_generic_run_buffer_in,
954     .enable_in = alsa_enable_in,
955 };
956 
957 static struct audio_driver alsa_audio_driver = {
958     .name           = "alsa",
959     .descr          = "ALSA http://www.alsa-project.org",
960     .init           = alsa_audio_init,
961     .fini           = alsa_audio_fini,
962     .pcm_ops        = &alsa_pcm_ops,
963     .can_be_default = 1,
964     .max_voices_out = INT_MAX,
965     .max_voices_in  = INT_MAX,
966     .voice_size_out = sizeof (ALSAVoiceOut),
967     .voice_size_in  = sizeof (ALSAVoiceIn)
968 };
969 
970 static void register_audio_alsa(void)
971 {
972     audio_driver_register(&alsa_audio_driver);
973 }
974 type_init(register_audio_alsa);
975