xref: /openbmc/qemu/audio/alsaaudio.c (revision da1034094d375afe9e3d8ec8980550ea0f06f7e0)
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  
alsa_logerr(int err,const char * fmt,...)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  
alsa_logerr2(int err,const char * typ,const char * fmt,...)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  
alsa_fini_poll(struct pollhlp * hlp)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  
alsa_anal_close1(snd_pcm_t ** handlep)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  
alsa_anal_close(snd_pcm_t ** handlep,struct pollhlp * hlp)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  
alsa_recover(snd_pcm_t * handle)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  
alsa_resume(snd_pcm_t * handle)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  
alsa_poll_handler(void * opaque)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  
alsa_poll_helper(snd_pcm_t * handle,struct pollhlp * hlp,int mask)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  
alsa_poll_out(HWVoiceOut * hw)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  
alsa_poll_in(HWVoiceIn * hw)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  
aud_to_alsafmt(AudioFormat fmt,int endianness)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  
alsa_to_audfmt(snd_pcm_format_t alsafmt,AudioFormat * fmt,int * endianness)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  
alsa_dump_info(struct alsa_params_req * req,struct alsa_params_obt * obt,snd_pcm_format_t obtfmt,AudiodevAlsaPerDirectionOptions * apdo)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  
alsa_set_threshold(snd_pcm_t * handle,snd_pcm_uframes_t threshold)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  
alsa_open(bool in,struct alsa_params_req * req,struct alsa_params_obt * obt,snd_pcm_t ** handlep,Audiodev * dev)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  
alsa_buffer_get_free(HWVoiceOut * hw)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  
alsa_write(HWVoiceOut * hw,void * buf,size_t len)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  
alsa_fini_out(HWVoiceOut * hw)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  
alsa_init_out(HWVoiceOut * hw,struct audsettings * as,void * drv_opaque)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  
alsa_voice_ctl(snd_pcm_t * handle,const char * typ,int ctl)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  
alsa_enable_out(HWVoiceOut * hw,bool enable)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  
alsa_init_in(HWVoiceIn * hw,struct audsettings * as,void * drv_opaque)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  
alsa_fini_in(HWVoiceIn * hw)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  
alsa_read(HWVoiceIn * hw,void * buf,size_t len)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  
alsa_enable_in(HWVoiceIn * hw,bool enable)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  
alsa_init_per_direction(AudiodevAlsaPerDirectionOptions * apdo)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  
alsa_audio_init(Audiodev * dev,Error ** errp)907  static void *alsa_audio_init(Audiodev *dev, Error **errp)
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  
alsa_audio_fini(void * opaque)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      .max_voices_out = INT_MAX,
964      .max_voices_in  = INT_MAX,
965      .voice_size_out = sizeof (ALSAVoiceOut),
966      .voice_size_in  = sizeof (ALSAVoiceIn)
967  };
968  
register_audio_alsa(void)969  static void register_audio_alsa(void)
970  {
971      audio_driver_register(&alsa_audio_driver);
972  }
973  type_init(register_audio_alsa);
974