/[qemu]/qemu/audio/alsaaudio.c
ViewVC logotype

Diff of /qemu/audio/alsaaudio.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.3 by bellard, Fri Nov 11 00:06:10 2005 UTC revision 1.4 by bellard, Sun Nov 20 16:24:34 2005 UTC
# Line 31  typedef struct ALSAVoiceOut { Line 31  typedef struct ALSAVoiceOut {
31      HWVoiceOut hw;      HWVoiceOut hw;
32      void *pcm_buf;      void *pcm_buf;
33      snd_pcm_t *handle;      snd_pcm_t *handle;
     int can_pause;  
     int was_enabled;  
34  } ALSAVoiceOut;  } ALSAVoiceOut;
35    
36  typedef struct ALSAVoiceIn {  typedef struct ALSAVoiceIn {
37      HWVoiceIn hw;      HWVoiceIn hw;
38      snd_pcm_t *handle;      snd_pcm_t *handle;
39      void *pcm_buf;      void *pcm_buf;
     int can_pause;  
40  } ALSAVoiceIn;  } ALSAVoiceIn;
41    
42  static struct {  static struct {
# Line 58  static struct { Line 55  static struct {
55    
56      int buffer_size_out_overriden;      int buffer_size_out_overriden;
57      int period_size_out_overriden;      int period_size_out_overriden;
58        int verbose;
59  } conf = {  } conf = {
60  #ifdef HIGH_LATENCY  #ifdef HIGH_LATENCY
61      .size_in_usec_in = 1,      .size_in_usec_in = 1,
# Line 73  static struct { Line 71  static struct {
71  #else  #else
72  #define DEFAULT_BUFFER_SIZE 1024  #define DEFAULT_BUFFER_SIZE 1024
73  #define DEFAULT_PERIOD_SIZE 256  #define DEFAULT_PERIOD_SIZE 256
74      .buffer_size_in = DEFAULT_BUFFER_SIZE,      .buffer_size_in = DEFAULT_BUFFER_SIZE * 4,
75      .period_size_in = DEFAULT_PERIOD_SIZE,      .period_size_in = DEFAULT_PERIOD_SIZE * 4,
76      .buffer_size_out = DEFAULT_BUFFER_SIZE,      .buffer_size_out = DEFAULT_BUFFER_SIZE,
77      .period_size_out = DEFAULT_PERIOD_SIZE,      .period_size_out = DEFAULT_PERIOD_SIZE,
78      .buffer_size_in_overriden = 0,      .buffer_size_in_overriden = 0,
# Line 82  static struct { Line 80  static struct {
80      .period_size_in_overriden = 0,      .period_size_in_overriden = 0,
81      .period_size_out_overriden = 0,      .period_size_out_overriden = 0,
82  #endif  #endif
83      .threshold = 0      .threshold = 0,
84        .verbose = 0
85  };  };
86    
87  struct alsa_params_req {  struct alsa_params_req {
# Line 97  struct alsa_params_obt { Line 96  struct alsa_params_obt {
96      int freq;      int freq;
97      audfmt_e fmt;      audfmt_e fmt;
98      int nchannels;      int nchannels;
     int can_pause;  
99      snd_pcm_uframes_t samples;      snd_pcm_uframes_t samples;
100  };  };
101    
# Line 474  static int alsa_open (int in, struct als Line 472  static int alsa_open (int in, struct als
472          goto err;          goto err;
473      }      }
474    
     obt->can_pause = snd_pcm_hw_params_can_pause (hw_params);  
     if (obt->can_pause < 0) {  
         alsa_logerr (err, "Could not get pause capability for %s\n", typ);  
         obt->can_pause = 0;  
     }  
   
475      if (!in && conf.threshold) {      if (!in && conf.threshold) {
476          snd_pcm_uframes_t threshold;          snd_pcm_uframes_t threshold;
477          int bytes_per_sec;          int bytes_per_sec;
# Line 527  static int alsa_recover (snd_pcm_t *hand Line 519  static int alsa_recover (snd_pcm_t *hand
519      return 0;      return 0;
520  }  }
521    
522    static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
523    {
524        snd_pcm_sframes_t avail;
525    
526        avail = snd_pcm_avail_update (handle);
527        if (avail < 0) {
528            if (avail == -EPIPE) {
529                if (!alsa_recover (handle)) {
530                    avail = snd_pcm_avail_update (handle);
531                }
532            }
533    
534            if (avail < 0) {
535                alsa_logerr (avail,
536                             "Could not obtain number of available frames\n");
537                return -1;
538            }
539        }
540    
541        return avail;
542    }
543    
544  static int alsa_run_out (HWVoiceOut *hw)  static int alsa_run_out (HWVoiceOut *hw)
545  {  {
546      ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;      ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
# Line 541  static int alsa_run_out (HWVoiceOut *hw) Line 555  static int alsa_run_out (HWVoiceOut *hw)
555          return 0;          return 0;
556      }      }
557    
558      avail = snd_pcm_avail_update (alsa->handle);      avail = alsa_get_avail (alsa->handle);
559      if (avail < 0) {      if (avail < 0) {
560          if (avail == -EPIPE) {          dolog ("Could not get number of available playback frames\n");
             if (!alsa_recover (alsa->handle)) {  
                 avail = snd_pcm_avail_update (alsa->handle);  
                 if (avail >= 0) {  
                     goto ok;  
                 }  
             }  
         }  
   
         alsa_logerr (avail, "Could not get amount free space\n");  
561          return 0;          return 0;
562      }      }
563    
  ok:  
564      decr = audio_MIN (live, avail);      decr = audio_MIN (live, avail);
565      samples = decr;      samples = decr;
566      rpos = hw->rpos;      rpos = hw->rpos;
567      while (samples) {      while (samples) {
568          int left_till_end_samples = hw->samples - rpos;          int left_till_end_samples = hw->samples - rpos;
569          int convert_samples = audio_MIN (samples, left_till_end_samples);          int len = audio_MIN (samples, left_till_end_samples);
570          snd_pcm_sframes_t written;          snd_pcm_sframes_t written;
571    
572          src = hw->mix_buf + rpos;          src = hw->mix_buf + rpos;
573          dst = advance (alsa->pcm_buf, rpos << hw->info.shift);          dst = advance (alsa->pcm_buf, rpos << hw->info.shift);
574    
575          hw->clip (dst, src, convert_samples);          hw->clip (dst, src, len);
576    
577          while (convert_samples) {          while (len) {
578              written = snd_pcm_writei (alsa->handle, dst, convert_samples);              written = snd_pcm_writei (alsa->handle, dst, len);
579    
580              if (written < 0) {              if (written <= 0) {
581                  switch (written) {                  switch (written) {
582                  case -EPIPE:                  case 0:
583                      if (!alsa_recover (alsa->handle)) {                      if (conf.verbose) {
584                          continue;                          dolog ("Failed to write %d frames (wrote zero)\n", len);
585                      }                      }
                     dolog ("Failed to write %d frames to %p, "  
                            "handle %p not prepared\n",  
                            convert_samples,  
                            dst,  
                            alsa->handle);  
586                      goto exit;                      goto exit;
587    
588                  case -EAGAIN:                  case -EPIPE:
589                        if (alsa_recover (alsa->handle)) {
590                            alsa_logerr (written, "Failed to write %d frames\n",
591                                         len);
592                            goto exit;
593                        }
594                        if (conf.verbose) {
595                            dolog ("Recovering from playback xrun\n");
596                        }
597                      continue;                      continue;
598    
599                    case -EAGAIN:
600                        goto exit;
601    
602                  default:                  default:
603                      alsa_logerr (written, "Failed to write %d frames to %p\n",                      alsa_logerr (written, "Failed to write %d frames to %p\n",
604                                   convert_samples, dst);                                   len, dst);
605                      goto exit;                      goto exit;
606                  }                  }
607              }              }
# Line 599  static int alsa_run_out (HWVoiceOut *hw) Line 609  static int alsa_run_out (HWVoiceOut *hw)
609              mixeng_clear (src, written);              mixeng_clear (src, written);
610              rpos = (rpos + written) % hw->samples;              rpos = (rpos + written) % hw->samples;
611              samples -= written;              samples -= written;
612              convert_samples -= written;              len -= written;
613              dst = advance (dst, written << hw->info.shift);              dst = advance (dst, written << hw->info.shift);
614              src += written;              src += written;
615          }          }
# Line 659  static int alsa_init_out (HWVoiceOut *hw Line 669  static int alsa_init_out (HWVoiceOut *hw
669          &obt_as,          &obt_as,
670          audio_need_to_swap_endian (endianness)          audio_need_to_swap_endian (endianness)
671          );          );
     alsa->can_pause = obt.can_pause;  
672      hw->samples = obt.samples;      hw->samples = obt.samples;
673    
674      alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);      alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
# Line 671  static int alsa_init_out (HWVoiceOut *hw Line 680  static int alsa_init_out (HWVoiceOut *hw
680      }      }
681    
682      alsa->handle = handle;      alsa->handle = handle;
     alsa->was_enabled = 0;  
683      return 0;      return 0;
684  }  }
685    
686  static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)  static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
687  {  {
688      int err;      int err;
689    
690        if (pause) {
691            err = snd_pcm_drop (handle);
692            if (err < 0) {
693                alsa_logerr (err, "Could not stop %s", typ);
694                return -1;
695            }
696        }
697        else {
698            err = snd_pcm_prepare (handle);
699            if (err < 0) {
700                alsa_logerr (err, "Could not prepare handle for %s", typ);
701                return -1;
702            }
703        }
704    
705        return 0;
706    }
707    
708    static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
709    {
710      ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;      ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
711    
712      switch (cmd) {      switch (cmd) {
713      case VOICE_ENABLE:      case VOICE_ENABLE:
714          ldebug ("enabling voice\n");          ldebug ("enabling voice\n");
715          audio_pcm_info_clear_buf (&hw->info, alsa->pcm_buf, hw->samples);          return alsa_voice_ctl (alsa->handle, "playback", 0);
         if (alsa->can_pause) {  
             /* Why this was_enabled madness is needed at all?? */  
             if (alsa->was_enabled) {  
                 err = snd_pcm_pause (alsa->handle, 0);  
                 if (err < 0) {  
                     alsa_logerr (err, "Failed to resume playing\n");  
                     /* not fatal really */  
                 }  
             }  
             else {  
                 alsa->was_enabled = 1;  
             }  
         }  
         break;  
716    
717      case VOICE_DISABLE:      case VOICE_DISABLE:
718          ldebug ("disabling voice\n");          ldebug ("disabling voice\n");
719          if (alsa->can_pause) {          return alsa_voice_ctl (alsa->handle, "playback", 1);
             err = snd_pcm_pause (alsa->handle, 1);  
             if (err < 0) {  
                 alsa_logerr (err, "Failed to stop playing\n");  
                 /* not fatal really */  
             }  
         }  
         break;  
720      }      }
721      return 0;  
722        return -1;
723  }  }
724    
725  static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)  static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
# Line 749  static int alsa_init_in (HWVoiceIn *hw, Line 758  static int alsa_init_in (HWVoiceIn *hw,
758          &obt_as,          &obt_as,
759          audio_need_to_swap_endian (endianness)          audio_need_to_swap_endian (endianness)
760          );          );
     alsa->can_pause = obt.can_pause;  
761      hw->samples = obt.samples;      hw->samples = obt.samples;
762    
763      alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);      alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
# Line 783  static int alsa_run_in (HWVoiceIn *hw) Line 791  static int alsa_run_in (HWVoiceIn *hw)
791      int i;      int i;
792      int live = audio_pcm_hw_get_live_in (hw);      int live = audio_pcm_hw_get_live_in (hw);
793      int dead = hw->samples - live;      int dead = hw->samples - live;
794        int decr;
795      struct {      struct {
796          int add;          int add;
797          int len;          int len;
# Line 790  static int alsa_run_in (HWVoiceIn *hw) Line 799  static int alsa_run_in (HWVoiceIn *hw)
799          { hw->wpos, 0 },          { hw->wpos, 0 },
800          { 0, 0 }          { 0, 0 }
801      };      };
802        snd_pcm_sframes_t avail;
803      snd_pcm_uframes_t read_samples = 0;      snd_pcm_uframes_t read_samples = 0;
804    
805      if (!dead) {      if (!dead) {
806          return 0;          return 0;
807      }      }
808    
809      if (hw->wpos + dead > hw->samples) {      avail = alsa_get_avail (alsa->handle);
810        if (avail < 0) {
811            dolog ("Could not get number of captured frames\n");
812            return 0;
813        }
814    
815        if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
816            avail = hw->samples;
817        }
818    
819        decr = audio_MIN (dead, avail);
820        if (!decr) {
821            return 0;
822        }
823    
824        if (hw->wpos + decr > hw->samples) {
825          bufs[0].len = (hw->samples - hw->wpos);          bufs[0].len = (hw->samples - hw->wpos);
826          bufs[1].len = (dead - (hw->samples - hw->wpos));          bufs[1].len = (decr - (hw->samples - hw->wpos));
827      }      }
828      else {      else {
829          bufs[0].len = dead;          bufs[0].len = decr;
830      }      }
831    
   
832      for (i = 0; i < 2; ++i) {      for (i = 0; i < 2; ++i) {
833          void *src;          void *src;
834          st_sample_t *dst;          st_sample_t *dst;
# Line 820  static int alsa_run_in (HWVoiceIn *hw) Line 843  static int alsa_run_in (HWVoiceIn *hw)
843          while (len) {          while (len) {
844              nread = snd_pcm_readi (alsa->handle, src, len);              nread = snd_pcm_readi (alsa->handle, src, len);
845    
846              if (nread < 0) {              if (nread <= 0) {
847                  switch (nread) {                  switch (nread) {
848                  case -EPIPE:                  case 0:
849                      if (!alsa_recover (alsa->handle)) {                      if (conf.verbose) {
850                          continue;                          dolog ("Failed to read %ld frames (read zero)\n", len);
851                      }                      }
                     dolog (  
                         "Failed to read %ld frames from %p, "  
                         "handle %p not prepared\n",  
                         len,  
                         src,  
                         alsa->handle  
                         );  
852                      goto exit;                      goto exit;
853    
854                  case -EAGAIN:                  case -EPIPE:
855                        if (alsa_recover (alsa->handle)) {
856                            alsa_logerr (nread, "Failed to read %ld frames\n", len);
857                            goto exit;
858                        }
859                        if (conf.verbose) {
860                            dolog ("Recovering from capture xrun\n");
861                        }
862                      continue;                      continue;
863    
864                    case -EAGAIN:
865                        goto exit;
866    
867                  default:                  default:
868                      alsa_logerr (                      alsa_logerr (
869                          nread,                          nread,
# Line 871  static int alsa_read (SWVoiceIn *sw, voi Line 897  static int alsa_read (SWVoiceIn *sw, voi
897    
898  static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)  static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
899  {  {
900      (void) hw;      ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
901      (void) cmd;  
902      return 0;      switch (cmd) {
903        case VOICE_ENABLE:
904            ldebug ("enabling voice\n");
905            return alsa_voice_ctl (alsa->handle, "capture", 0);
906    
907        case VOICE_DISABLE:
908            ldebug ("disabling voice\n");
909            return alsa_voice_ctl (alsa->handle, "capture", 1);
910        }
911    
912        return -1;
913  }  }
914    
915  static void *alsa_audio_init (void)  static void *alsa_audio_init (void)
# Line 909  static struct audio_option alsa_options[ Line 945  static struct audio_option alsa_options[
945    
946      {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,      {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in,
947       "ADC device name", NULL, 0},       "ADC device name", NULL, 0},
948    
949        {"VERBOSE", AUD_OPT_BOOL, &conf.verbose,
950         "Behave in a more verbose way", NULL, 0},
951    
952      {NULL, 0, NULL, NULL, NULL, 0}      {NULL, 0, NULL, NULL, NULL, 0}
953  };  };
954    

Legend:
Removed from v.1.3  
changed lines
  Added in v.1.4

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26