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