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

Diff of /qemu/audio/audio.c

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

revision 1.5 by bellard, Mon Dec 6 23:14:48 2004 UTC revision 1.6 by bellard, Sun Oct 30 18:58:22 2005 UTC
# Line 1  Line 1 
1  /*  /*
2   * QEMU Audio subsystem   * QEMU Audio subsystem
3   *   *
4   * Copyright (c) 2003-2004 Vassili Karpov (malc)   * Copyright (c) 2003-2005 Vassili Karpov (malc)
5   *   *
6   * Permission is hereby granted, free of charge, to any person obtaining a copy   * 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   * of this software and associated documentation files (the "Software"), to deal
8   * in the Software without restriction, including without limitation the rights   * in the Software without restriction, including without limitation the rights
# Line 21  Line 21 
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22   * THE SOFTWARE.   * THE SOFTWARE.
23   */   */
 #include <assert.h>  
24  #include "vl.h"  #include "vl.h"
25    
26  #define USE_WAV_AUDIO  #define AUDIO_CAP "audio"
27    #include "audio_int.h"
28    
29  #include "audio/audio_int.h"  static void audio_pcm_hw_fini_in (HWVoiceIn *hw);
30    static void audio_pcm_hw_fini_out (HWVoiceOut *hw);
31    
32  #define dolog(...) AUD_log ("audio", __VA_ARGS__)  static LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
33  #ifdef DEBUG  static LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
 #define ldebug(...) dolog (__VA_ARGS__)  
 #else  
 #define ldebug(...)  
 #endif  
34    
35  #define QC_AUDIO_DRV    "QEMU_AUDIO_DRV"  /* #define DEBUG_PLIVE */
36  #define QC_VOICES       "QEMU_VOICES"  /* #define DEBUG_LIVE */
37  #define QC_FIXED_FORMAT "QEMU_FIXED_FORMAT"  /* #define DEBUG_OUT */
 #define QC_FIXED_FREQ   "QEMU_FIXED_FREQ"  
38    
39  static HWVoice *hw_voices;  static struct audio_driver *drvtab[] = {
40    #ifdef CONFIG_OSS
41        &oss_audio_driver,
42    #endif
43    #ifdef CONFIG_ALSA
44        &alsa_audio_driver,
45    #endif
46    #ifdef CONFIG_COREAUDIO
47        &coreaudio_audio_driver,
48    #endif
49    #ifdef CONFIG_DSOUND
50        &dsound_audio_driver,
51    #endif
52    #ifdef CONFIG_FMOD
53        &fmod_audio_driver,
54    #endif
55    #ifdef CONFIG_SDL
56        &sdl_audio_driver,
57    #endif
58        &no_audio_driver,
59        &wav_audio_driver
60    };
61    
62  AudioState audio_state = {  AudioState audio_state = {
63        /* Out */
64        1,                          /* use fixed settings */
65        44100,                      /* fixed frequency */
66        2,                          /* fixed channels */
67        AUD_FMT_S16,                /* fixed format */
68        1,                          /* number of hw voices */
69        1,                          /* greedy */
70    
71        /* In */
72      1,                          /* use fixed settings */      1,                          /* use fixed settings */
73      44100,                      /* fixed frequency */      44100,                      /* fixed frequency */
74      2,                          /* fixed channels */      2,                          /* fixed channels */
75      AUD_FMT_S16,                /* fixed format */      AUD_FMT_S16,                /* fixed format */
76      1,                          /* number of hw voices */      1,                          /* number of hw voices */
77      -1                          /* voice size */      1,                          /* greedy */
78    
79        NULL,                       /* driver opaque */
80        NULL,                       /* driver */
81    
82        NULL,                       /* timer handle */
83        { 0 },                      /* period */
84        0                           /* plive */
85    };
86    
87    volume_t nominal_volume = {
88        0,
89    #ifdef FLOAT_MIXENG
90        1.0,
91        1.0
92    #else
93        UINT_MAX,
94        UINT_MAX
95    #endif
96  };  };
97    
98  /* http://www.df.lth.se/~john_e/gems/gem002d.html */  /* http://www.df.lth.se/~john_e/gems/gem002d.html */
# Line 68  inline uint32_t lsbindex (uint32_t u) Line 112  inline uint32_t lsbindex (uint32_t u)
112      return popcount ((u&-u)-1);      return popcount ((u&-u)-1);
113  }  }
114    
115  int audio_get_conf_int (const char *key, int defval)  #ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED
116    #error No its not
117    #else
118    int audio_bug (const char *funcname, int cond)
119    {
120        if (cond) {
121            static int shown;
122    
123            AUD_log (NULL, "Error a bug that was just triggered in %s\n", funcname);
124            if (!shown) {
125                shown = 1;
126                AUD_log (NULL, "Save all your work and restart without audio\n");
127                AUD_log (NULL, "Please send bug report to malc@pulsesoft.com\n");
128                AUD_log (NULL, "I am sorry\n");
129            }
130            AUD_log (NULL, "Context:\n");
131    
132    #if defined AUDIO_BREAKPOINT_ON_BUG
133    #  if defined HOST_I386
134    #    if defined __GNUC__
135            __asm__ ("int3");
136    #    elif defined _MSC_VER
137            _asm _emit 0xcc;
138    #    else
139            abort ();
140    #    endif
141    #  else
142            abort ();
143    #  endif
144    #endif
145        }
146    
147        return cond;
148    }
149    #endif
150    
151    static char *audio_alloc_prefix (const char *s)
152  {  {
153      int val = defval;      const char qemu_prefix[] = "QEMU_";
154        size_t len;
155        char *r;
156    
157        if (!s) {
158            return NULL;
159        }
160    
161        len = strlen (s);
162        r = qemu_malloc (len + sizeof (qemu_prefix));
163    
164        if (r) {
165            size_t i;
166            char *u = r + sizeof (qemu_prefix) - 1;
167    
168            strcpy (r, qemu_prefix);
169            strcat (r, s);
170    
171            for (i = 0; i < len; ++i) {
172                u[i] = toupper (u[i]);
173            }
174        }
175        return r;
176    }
177    
178    const char *audio_audfmt_to_string (audfmt_e fmt)
179    {
180        switch (fmt) {
181        case AUD_FMT_U8:
182            return "U8";
183    
184        case AUD_FMT_U16:
185            return "U16";
186    
187        case AUD_FMT_S8:
188            return "S8";
189    
190        case AUD_FMT_S16:
191            return "S16";
192        }
193    
194        dolog ("Bogus audfmt %d returning S16\n", fmt);
195        return "S16";
196    }
197    
198    audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, int *defaultp)
199    {
200        if (!strcasecmp (s, "u8")) {
201            *defaultp = 0;
202            return AUD_FMT_U8;
203        }
204        else if (!strcasecmp (s, "u16")) {
205            *defaultp = 0;
206            return AUD_FMT_U16;
207        }
208        else if (!strcasecmp (s, "s8")) {
209            *defaultp = 0;
210            return AUD_FMT_S8;
211        }
212        else if (!strcasecmp (s, "s16")) {
213            *defaultp = 0;
214            return AUD_FMT_S16;
215        }
216        else {
217            dolog ("Bogus audio format `%s' using %s\n",
218                   s, audio_audfmt_to_string (defval));
219            *defaultp = 1;
220            return defval;
221        }
222    }
223    
224    static audfmt_e audio_get_conf_fmt (const char *envname,
225                                        audfmt_e defval,
226                                        int *defaultp)
227    {
228        const char *var = getenv (envname);
229        if (!var) {
230            *defaultp = 1;
231            return defval;
232        }
233        return audio_string_to_audfmt (var, defval, defaultp);
234    }
235    
236    static int audio_get_conf_int (const char *key, int defval, int *defaultp)
237    {
238        int val;
239      char *strval;      char *strval;
240    
241      strval = getenv (key);      strval = getenv (key);
242      if (strval) {      if (strval) {
243            *defaultp = 0;
244          val = atoi (strval);          val = atoi (strval);
245            return val;
246        }
247        else {
248            *defaultp = 1;
249            return defval;
250      }      }
   
     return val;  
251  }  }
252    
253  const char *audio_get_conf_str (const char *key, const char *defval)  static const char *audio_get_conf_str (const char *key,
254                                           const char *defval,
255                                           int *defaultp)
256  {  {
257      const char *val = getenv (key);      const char *val = getenv (key);
258      if (!val)      if (!val) {
259            *defaultp = 1;
260          return defval;          return defval;
261      else      }
262        else {
263            *defaultp = 0;
264          return val;          return val;
265        }
266  }  }
267    
268  void AUD_log (const char *cap, const char *fmt, ...)  void AUD_log (const char *cap, const char *fmt, ...)
269  {  {
270      va_list ap;      va_list ap;
271      fprintf (stderr, "%s: ", cap);      if (cap) {
272            fprintf (stderr, "%s: ", cap);
273        }
274      va_start (ap, fmt);      va_start (ap, fmt);
275      vfprintf (stderr, fmt, ap);      vfprintf (stderr, fmt, ap);
276      va_end (ap);      va_end (ap);
277  }  }
278    
279  /*  void AUD_vlog (const char *cap, const char *fmt, va_list ap)
  * Soft Voice  
  */  
 void pcm_sw_free_resources (SWVoice *sw)  
280  {  {
281      if (sw->buf) qemu_free (sw->buf);      if (cap) {
282      if (sw->rate) st_rate_stop (sw->rate);          fprintf (stderr, "%s: ", cap);
283      sw->buf = NULL;      }
284      sw->rate = NULL;      vfprintf (stderr, fmt, ap);
285  }  }
286    
287  int pcm_sw_alloc_resources (SWVoice *sw)  static void audio_print_options (const char *prefix,
288                                     struct audio_option *opt)
289  {  {
290      sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));      char *uprefix;
     if (!sw->buf)  
         return -1;  
291    
292      sw->rate = st_rate_start (sw->freq, sw->hw->freq);      if (!prefix) {
293      if (!sw->rate) {          dolog ("No prefix specified\n");
294          qemu_free (sw->buf);          return;
         sw->buf = NULL;  
         return -1;  
295      }      }
296      return 0;  
297        if (!opt) {
298            dolog ("No options\n");
299            return;
300        }
301    
302        uprefix = audio_alloc_prefix (prefix);
303    
304        for (; opt->name; opt++) {
305            const char *state = "default";
306            printf ("  %s_%s: ", uprefix, opt->name);
307    
308            if (opt->overridenp && *opt->overridenp) {
309                state = "current";
310            }
311    
312            switch (opt->tag) {
313            case AUD_OPT_BOOL:
314                {
315                    int *intp = opt->valp;
316                    printf ("boolean, %s = %d\n", state, *intp ? 1 : 0);
317                }
318                break;
319    
320            case AUD_OPT_INT:
321                {
322                    int *intp = opt->valp;
323                    printf ("integer, %s = %d\n", state, *intp);
324                }
325                break;
326    
327            case AUD_OPT_FMT:
328                {
329                    audfmt_e *fmtp = opt->valp;
330                    printf (
331                        "format, %s = %s, (one of: U8 S8 U16 S16)\n",
332                        state,
333                        audio_audfmt_to_string (*fmtp)
334                        );
335                }
336                break;
337    
338            case AUD_OPT_STR:
339                {
340                    const char **strp = opt->valp;
341                    printf ("string, %s = %s\n",
342                            state,
343                            *strp ? *strp : "(not set)");
344                }
345                break;
346    
347            default:
348                printf ("???\n");
349                dolog ("Bad value tag for option %s_%s %d\n",
350                       uprefix, opt->name, opt->tag);
351                break;
352            }
353            printf ("    %s\n", opt->descr);
354        }
355    
356        qemu_free (uprefix);
357  }  }
358    
359  void pcm_sw_fini (SWVoice *sw)  static void audio_process_options (const char *prefix,
360                                       struct audio_option *opt)
361  {  {
362      pcm_sw_free_resources (sw);      char *optname;
363        const char qemu_prefix[] = "QEMU_";
364        size_t preflen;
365    
366        if (audio_bug (AUDIO_FUNC, !prefix)) {
367            dolog ("prefix = NULL\n");
368            return;
369        }
370    
371        if (audio_bug (AUDIO_FUNC, !opt)) {
372            dolog ("opt = NULL\n");
373            return;
374        }
375    
376        preflen = strlen (prefix);
377    
378        for (; opt->name; opt++) {
379            size_t len, i;
380            int def;
381    
382            if (!opt->valp) {
383                dolog ("Option value pointer for `%s' is not set\n",
384                       opt->name);
385                continue;
386            }
387    
388            len = strlen (opt->name);
389            optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1);
390            if (!optname) {
391                dolog ("Can not allocate memory for option name `%s'\n",
392                       opt->name);
393                continue;
394            }
395    
396            strcpy (optname, qemu_prefix);
397            for (i = 0; i <= preflen; ++i) {
398                optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]);
399            }
400            strcat (optname, "_");
401            strcat (optname, opt->name);
402    
403            def = 1;
404            switch (opt->tag) {
405            case AUD_OPT_BOOL:
406            case AUD_OPT_INT:
407                {
408                    int *intp = opt->valp;
409                    *intp = audio_get_conf_int (optname, *intp, &def);
410                }
411                break;
412    
413            case AUD_OPT_FMT:
414                {
415                    audfmt_e *fmtp = opt->valp;
416                    *fmtp = audio_get_conf_fmt (optname, *fmtp, &def);
417                }
418                break;
419    
420            case AUD_OPT_STR:
421                {
422                    const char **strp = opt->valp;
423                    *strp = audio_get_conf_str (optname, *strp, &def);
424                }
425                break;
426    
427            default:
428                dolog ("Bad value tag for option `%s' - %d\n",
429                       optname, opt->tag);
430                break;
431            }
432    
433            if (!opt->overridenp) {
434                opt->overridenp = &opt->overriden;
435            }
436            *opt->overridenp = !def;
437            qemu_free (optname);
438        }
439  }  }
440    
441  int pcm_sw_init (SWVoice *sw, HWVoice *hw, int freq,  static int audio_pcm_info_eq (struct audio_pcm_info *info, int freq,
442                   int nchannels, audfmt_e fmt)                                int nchannels, audfmt_e fmt)
443  {  {
444      int bits = 8, sign = 0;      int bits = 8, sign = 0;
445    
# Line 147  int pcm_sw_init (SWVoice *sw, HWVoice *h Line 455  int pcm_sw_init (SWVoice *sw, HWVoice *h
455          bits = 16;          bits = 16;
456          break;          break;
457      }      }
458        return info->freq == freq
459            && info->nchannels == nchannels
460            && info->sign == sign
461            && info->bits == bits;
462    }
463    
464      sw->hw = hw;  void audio_pcm_init_info (struct audio_pcm_info *info, int freq,
465      sw->freq = freq;                            int nchannels, audfmt_e fmt, int swap_endian)
466      sw->fmt = fmt;  {
467      sw->nchannels = nchannels;      int bits = 8, sign = 0;
     sw->shift = (nchannels == 2) + (bits == 16);  
     sw->align = (1 << sw->shift) - 1;  
     sw->left = 0;  
     sw->pos = 0;  
     sw->wpos = 0;  
     sw->live = 0;  
     sw->ratio = (sw->hw->freq * ((int64_t) INT_MAX)) / sw->freq;  
     sw->bytes_per_second = sw->freq << sw->shift;  
     sw->conv = mixeng_conv[nchannels == 2][sign][bits == 16];  
468    
469      pcm_sw_free_resources (sw);      switch (fmt) {
470      return pcm_sw_alloc_resources (sw);      case AUD_FMT_S8:
471            sign = 1;
472        case AUD_FMT_U8:
473            break;
474    
475        case AUD_FMT_S16:
476            sign = 1;
477        case AUD_FMT_U16:
478            bits = 16;
479            break;
480        }
481    
482        info->freq = freq;
483        info->bits = bits;
484        info->sign = sign;
485        info->nchannels = nchannels;
486        info->shift = (nchannels == 2) + (bits == 16);
487        info->align = (1 << info->shift) - 1;
488        info->bytes_per_second = info->freq << info->shift;
489        info->swap_endian = swap_endian;
490  }  }
491    
492  /* Hard voice */  void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
 void pcm_hw_free_resources (HWVoice *hw)  
493  {  {
494      if (hw->mix_buf)      if (!len) {
495          qemu_free (hw->mix_buf);          return;
496      hw->mix_buf = NULL;      }
497    
498        if (info->sign) {
499            memset (buf, len << info->shift, 0x00);
500        }
501        else {
502            if (info->bits == 8) {
503                memset (buf, len << info->shift, 0x80);
504            }
505            else {
506                int i;
507                uint16_t *p = buf;
508                int shift = info->nchannels - 1;
509                short s = INT16_MAX;
510    
511                if (info->swap_endian) {
512                    s = bswap16 (s);
513                }
514    
515                for (i = 0; i < len << shift; i++) {
516                    p[i] = s;
517                }
518            }
519        }
520  }  }
521    
522  int pcm_hw_alloc_resources (HWVoice *hw)  /*
523     * Hard voice (capture)
524     */
525    static void audio_pcm_hw_free_resources_in (HWVoiceIn *hw)
526  {  {
527      hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));      if (hw->conv_buf) {
528      if (!hw->mix_buf)          qemu_free (hw->conv_buf);
529          return -1;      }
530      return 0;      hw->conv_buf = NULL;
531  }  }
532    
533  void pcm_hw_fini (HWVoice *hw)  static int audio_pcm_hw_alloc_resources_in (HWVoiceIn *hw)
534  {  {
535      if (hw->active) {      hw->conv_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
536          ldebug ("pcm_hw_fini: %d %d %d\n", hw->freq, hw->nchannels, hw->fmt);      if (!hw->conv_buf) {
537          pcm_hw_free_resources (hw);          return -1;
         hw->pcm_ops->fini (hw);  
         memset (hw, 0, audio_state.drv->voice_size);  
538      }      }
539        return 0;
540  }  }
541    
542  void pcm_hw_gc (HWVoice *hw)  static int audio_pcm_hw_init_in (HWVoiceIn *hw, int freq, int nchannels, audfmt_e fmt)
543  {  {
544      if (hw->nb_voices)      audio_pcm_hw_fini_in (hw);
         return;  
545    
546      pcm_hw_fini (hw);      if (hw->pcm_ops->init_in (hw, freq, nchannels, fmt)) {
547            memset (hw, 0, audio_state.drv->voice_size_in);
548            return -1;
549        }
550        LIST_INIT (&hw->sw_head);
551        hw->active = 1;
552        hw->samples = hw->bufsize >> hw->info.shift;
553        hw->conv =
554            mixeng_conv
555            [nchannels == 2]
556            [hw->info.sign]
557            [hw->info.swap_endian]
558            [hw->info.bits == 16];
559        if (audio_pcm_hw_alloc_resources_in (hw)) {
560            audio_pcm_hw_free_resources_in (hw);
561            return -1;
562        }
563        return 0;
564  }  }
565    
566  int pcm_hw_get_live (HWVoice *hw)  static uint64_t audio_pcm_hw_find_min_in (HWVoiceIn *hw)
567  {  {
568      int i, alive = 0, live = hw->samples;      SWVoiceIn *sw;
569        int m = hw->total_samples_captured;
570    
571      for (i = 0; i < hw->nb_voices; i++) {      for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
572          if (hw->pvoice[i]->live) {          if (sw->active) {
573              live = audio_MIN (hw->pvoice[i]->live, live);              m = audio_MIN (m, sw->total_hw_samples_acquired);
             alive += 1;  
574          }          }
575      }      }
576        return m;
577    }
578    
579      if (alive)  int audio_pcm_hw_get_live_in (HWVoiceIn *hw)
580          return live;  {
581      else      int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw);
582          return -1;      if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
583            dolog ("live=%d hw->samples=%d\n", live, hw->samples);
584            return 0;
585        }
586        return live;
587  }  }
588    
589  int pcm_hw_get_live2 (HWVoice *hw, int *nb_active)  /*
590     * Soft voice (capture)
591     */
592    static void audio_pcm_sw_free_resources_in (SWVoiceIn *sw)
593  {  {
594      int i, alive = 0, live = hw->samples;      if (sw->conv_buf) {
595            qemu_free (sw->conv_buf);
596        }
597    
598      *nb_active = 0;      if (sw->rate) {
599      for (i = 0; i < hw->nb_voices; i++) {          st_rate_stop (sw->rate);
         if (hw->pvoice[i]->live) {  
             if (hw->pvoice[i]->live < live) {  
                 *nb_active = hw->pvoice[i]->active != 0;  
                 live = hw->pvoice[i]->live;  
             }  
             alive += 1;  
         }  
600      }      }
601    
602      if (alive)      sw->conv_buf = NULL;
603          return live;      sw->rate = NULL;
     else  
         return -1;  
604  }  }
605    
606  void pcm_hw_dec_live (HWVoice *hw, int decr)  static int audio_pcm_sw_alloc_resources_in (SWVoiceIn *sw)
607  {  {
608      int i;      int samples = ((int64_t) sw->hw->samples << 32) / sw->ratio;
609        sw->conv_buf = qemu_mallocz (samples * sizeof (st_sample_t));
610        if (!sw->conv_buf) {
611            return -1;
612        }
613    
614      for (i = 0; i < hw->nb_voices; i++) {      sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq);
615          if (hw->pvoice[i]->live) {      if (!sw->rate) {
616              hw->pvoice[i]->live -= decr;          qemu_free (sw->conv_buf);
617          }          sw->conv_buf = NULL;
618            return -1;
619      }      }
620        return 0;
621  }  }
622    
623  void pcm_hw_clear (HWVoice *hw, void *buf, int len)  static int audio_pcm_sw_init_in (SWVoiceIn *sw, HWVoiceIn *hw, const char *name,
624                               int freq, int nchannels, audfmt_e fmt)
625  {  {
626      if (!len)      audio_pcm_init_info (&sw->info, freq, nchannels, fmt,
627          return;                           /* None of the cards emulated by QEMU are big-endian
628                                hence following shortcut */
629                             audio_need_to_swap_endian (0));
630        sw->hw = hw;
631        sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
632    
633      switch (hw->fmt) {      sw->clip =
634      case AUD_FMT_S16:          mixeng_clip
635      case AUD_FMT_S8:          [nchannels == 2]
636          memset (buf, len << hw->shift, 0x00);          [sw->info.sign]
637          break;          [sw->info.swap_endian]
638            [sw->info.bits == 16];
639    
640      case AUD_FMT_U8:      sw->name = qemu_strdup (name);
641          memset (buf, len << hw->shift, 0x80);      audio_pcm_sw_free_resources_in (sw);
642          break;      return audio_pcm_sw_alloc_resources_in (sw);
643    }
644    
645      case AUD_FMT_U16:  static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw)
646          {  {
647              unsigned int i;      HWVoiceIn *hw = sw->hw;
648              uint16_t *p = buf;      int live = hw->total_samples_captured - sw->total_hw_samples_acquired;
649              int shift = hw->nchannels - 1;      int rpos;
650    
651              for (i = 0; i < len << shift; i++) {      if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
652                  p[i] = INT16_MAX;          dolog ("live=%d hw->samples=%d\n", live, hw->samples);
653              }          return 0;
654          }      }
655          break;  
656        rpos = hw->wpos - live;
657        if (rpos >= 0) {
658            return rpos;
659        }
660        else {
661            return hw->samples + rpos;
662      }      }
663  }  }
664    
665  int pcm_hw_write (SWVoice *sw, void *buf, int size)  int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
666  {  {
667      int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;      HWVoiceIn *hw = sw->hw;
668      int ret = 0, pos = 0;      int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
669      if (!sw)      st_sample_t *src, *dst = sw->conv_buf;
         return size;  
670    
671      hwsamples = sw->hw->samples;      rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;
     samples = size >> sw->shift;  
672    
673      if (!sw->live) {      live = hw->total_samples_captured - sw->total_hw_samples_acquired;
674          sw->wpos = sw->hw->rpos;      if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
675            dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
676            return 0;
677        }
678    
679        samples = size >> sw->info.shift;
680        if (!live) {
681            return 0;
682      }      }
     wpos = sw->wpos;  
     live = sw->live;  
     dead = hwsamples - live;  
     swlim = (dead * ((int64_t) INT_MAX)) / sw->ratio;  
     swlim = audio_MIN (swlim, samples);  
683    
684      ldebug ("size=%d live=%d dead=%d swlim=%d wpos=%d\n",      swlim = (live * sw->ratio) >> 32;
685             size, live, dead, swlim, wpos);      swlim = audio_MIN (swlim, samples);
     if (swlim)  
         sw->conv (sw->buf, buf, swlim);  
686    
687      while (swlim) {      while (swlim) {
688          dead = hwsamples - live;          src = hw->conv_buf + rpos;
689          left = hwsamples - wpos;          isamp = hw->wpos - rpos;
690          blck = audio_MIN (dead, left);          /* XXX: <= ? */
691          if (!blck) {          if (isamp <= 0) {
692              /* dolog ("swlim=%d\n", swlim); */              isamp = hw->samples - rpos;
693            }
694    
695            if (!isamp) {
696              break;              break;
697          }          }
698          isamp = swlim;          osamp = swlim;
699          osamp = blck;  
700          st_rate_flow (sw->rate, sw->buf + pos, sw->hw->mix_buf + wpos, &isamp, &osamp);          if (audio_bug (AUDIO_FUNC, osamp < 0)) {
701          ret += isamp;              dolog ("osamp=%d\n", osamp);
702          swlim -= isamp;          }
703          pos += isamp;  
704          live += osamp;          st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
705          wpos = (wpos + osamp) % hwsamples;          swlim -= osamp;
706            rpos = (rpos + isamp) % hw->samples;
707            dst += osamp;
708            ret += osamp;
709            total += isamp;
710      }      }
711    
712      sw->wpos = wpos;      sw->clip (buf, sw->conv_buf, ret);
713      sw->live = live;      sw->total_hw_samples_acquired += total;
714      return ret << sw->shift;      return ret << sw->info.shift;
715  }  }
716    
717  int pcm_hw_init (HWVoice *hw, int freq, int nchannels, audfmt_e fmt)  /*
718     * Hard voice (playback)
719     */
720    static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep)
721  {  {
722      int sign = 0, bits = 8;      SWVoiceOut *sw;
723        int m = INT_MAX;
724        int nb_live = 0;
725    
726        for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
727            if (sw->active || !sw->empty) {
728                m = audio_MIN (m, sw->total_hw_samples_mixed);
729                nb_live += 1;
730            }
731        }
732    
733        *nb_livep = nb_live;
734        return m;
735    }
736    
737    static void audio_pcm_hw_free_resources_out (HWVoiceOut *hw)
738    {
739        if (hw->mix_buf) {
740            qemu_free (hw->mix_buf);
741        }
742    
743      pcm_hw_fini (hw);      hw->mix_buf = NULL;
744      ldebug ("pcm_hw_init: %d %d %d\n", freq, nchannels, fmt);  }
745      if (hw->pcm_ops->init (hw, freq, nchannels, fmt)) {  
746          memset (hw, 0, audio_state.drv->voice_size);  static int audio_pcm_hw_alloc_resources_out (HWVoiceOut *hw)
747    {
748        hw->mix_buf = qemu_mallocz (hw->samples * sizeof (st_sample_t));
749        if (!hw->mix_buf) {
750          return -1;          return -1;
751      }      }
752    
753      switch (hw->fmt) {      return 0;
754      case AUD_FMT_S8:  }
         sign = 1;  
     case AUD_FMT_U8:  
         break;  
755    
756      case AUD_FMT_S16:  static int audio_pcm_hw_init_out (HWVoiceOut *hw, int freq,
757          sign = 1;                              int nchannels, audfmt_e fmt)
758      case AUD_FMT_U16:  {
759          bits = 16;      audio_pcm_hw_fini_out (hw);
760          break;      if (hw->pcm_ops->init_out (hw, freq, nchannels, fmt)) {
761            memset (hw, 0, audio_state.drv->voice_size_out);
762            return -1;
763      }      }
764    
765      hw->nb_voices = 0;      LIST_INIT (&hw->sw_head);
766      hw->active = 1;      hw->active = 1;
767      hw->shift = (hw->nchannels == 2) + (bits == 16);      hw->samples = hw->bufsize >> hw->info.shift;
768      hw->bytes_per_second = hw->freq << hw->shift;      hw->clip =
769      hw->align = (1 << hw->shift) - 1;          mixeng_clip
770      hw->samples = hw->bufsize >> hw->shift;          [nchannels == 2]
771      hw->clip = mixeng_clip[hw->nchannels == 2][sign][bits == 16];          [hw->info.sign]
772      if (pcm_hw_alloc_resources (hw)) {          [hw->info.swap_endian]
773          pcm_hw_fini (hw);          [hw->info.bits == 16];
774        if (audio_pcm_hw_alloc_resources_out (hw)) {
775            audio_pcm_hw_fini_out (hw);
776          return -1;          return -1;
777      }      }
778      return 0;      return 0;
779  }  }
780    
781  static int dist (void *hw)  int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live)
782  {  {
783      if (hw) {      int smin;
784          return (((uint8_t *) hw - (uint8_t *) hw_voices)  
785                  / audio_state.drv->voice_size) + 1;      smin = audio_pcm_hw_find_min_out (hw, nb_live);
786    
787        if (!*nb_live) {
788            return 0;
789      }      }
790      else {      else {
791          return 0;          int live = smin;
792    
793            if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
794                dolog ("live=%d hw->samples=%d\n", live, hw->samples);
795                return 0;
796            }
797            return live;
798      }      }
799  }  }
800    
801  #define ADVANCE(hw) \  int audio_pcm_hw_get_live_out (HWVoiceOut *hw)
     ((hw) ? advance (hw, audio_state.drv->voice_size) : hw_voices)  
   
 HWVoice *pcm_hw_find_any (HWVoice *hw)  
802  {  {
803      int i = dist (hw);      int nb_live;
804      for (; i < audio_state.nb_hw_voices; i++) {      int live;
805          hw = ADVANCE (hw);  
806          return hw;      live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
807        if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
808            dolog ("live=%d hw->samples=%d\n", live, hw->samples);
809            return 0;
810      }      }
811      return NULL;      return live;
812  }  }
813    
814  HWVoice *pcm_hw_find_any_active (HWVoice *hw)  /*
815     * Soft voice (playback)
816     */
817    static void audio_pcm_sw_free_resources_out (SWVoiceOut *sw)
818  {  {
819      int i = dist (hw);      if (sw->buf) {
820      for (; i < audio_state.nb_hw_voices; i++) {          qemu_free (sw->buf);
         hw = ADVANCE (hw);  
         if (hw->active)  
             return hw;  
821      }      }
     return NULL;  
 }  
822    
823  HWVoice *pcm_hw_find_any_active_enabled (HWVoice *hw)      if (sw->rate) {
824  {          st_rate_stop (sw->rate);
     int i = dist (hw);  
     for (; i < audio_state.nb_hw_voices; i++) {  
         hw = ADVANCE (hw);  
         if (hw->active && hw->enabled)  
             return hw;  
825      }      }
826      return NULL;  
827        sw->buf = NULL;
828        sw->rate = NULL;
829  }  }
830    
831  HWVoice *pcm_hw_find_any_passive (HWVoice *hw)  static int audio_pcm_sw_alloc_resources_out (SWVoiceOut *sw)
832  {  {
833      int i = dist (hw);      sw->buf = qemu_mallocz (sw->hw->samples * sizeof (st_sample_t));
834      for (; i < audio_state.nb_hw_voices; i++) {      if (!sw->buf) {
835          hw = ADVANCE (hw);          return -1;
         if (!hw->active)  
             return hw;  
836      }      }
     return NULL;  
 }  
837    
838  HWVoice *pcm_hw_find_specific (HWVoice *hw, int freq,      sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq);
839                                 int nchannels, audfmt_e fmt)      if (!sw->rate) {
840  {          qemu_free (sw->buf);
841      while ((hw = pcm_hw_find_any_active (hw))) {          sw->buf = NULL;
842          if (hw->freq == freq &&          return -1;
             hw->nchannels == nchannels &&  
             hw->fmt == fmt)  
             return hw;  
843      }      }
844      return NULL;      return 0;
845    }
846    
847    static int audio_pcm_sw_init_out (SWVoiceOut *sw, HWVoiceOut *hw,
848                                const char *name, int freq,
849                                int nchannels, audfmt_e fmt)
850    {
851        audio_pcm_init_info (&sw->info, freq, nchannels, fmt,
852                             /* None of the cards emulated by QEMU are big-endian
853                                hence following shortcut */
854                             audio_need_to_swap_endian (0));
855        sw->hw = hw;
856        sw->empty = 1;
857        sw->active = 0;
858        sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq;
859        sw->total_hw_samples_mixed = 0;
860    
861        sw->conv =
862            mixeng_conv
863            [nchannels == 2]
864            [sw->info.sign]
865            [sw->info.swap_endian]
866            [sw->info.bits == 16];
867        sw->name = qemu_strdup (name);
868    
869        audio_pcm_sw_free_resources_out (sw);
870        return audio_pcm_sw_alloc_resources_out (sw);
871  }  }
872    
873  HWVoice *pcm_hw_add (int freq, int nchannels, audfmt_e fmt)  int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size)
874  {  {
875      HWVoice *hw;      int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck;
876        int ret = 0, pos = 0, total = 0;
877    
878        if (!sw) {
879            return size;
880        }
881    
882        hwsamples = sw->hw->samples;
883    
884      if (audio_state.fixed_format) {      live = sw->total_hw_samples_mixed;
885          freq = audio_state.fixed_freq;      if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){
886          nchannels = audio_state.fixed_channels;          dolog ("live=%d hw->samples=%d\n", live, hwsamples);
887          fmt = audio_state.fixed_fmt;          return 0;
888      }      }
889    
890      hw = pcm_hw_find_specific (NULL, freq, nchannels, fmt);      if (live == hwsamples) {
891            return 0;
892        }
893    
894      if (hw)      wpos = (sw->hw->rpos + live) % hwsamples;
895          return hw;      samples = size >> sw->info.shift;
896    
897      hw = pcm_hw_find_any_passive (NULL);      dead = hwsamples - live;
898      if (hw) {      swlim = ((int64_t) dead << 32) / sw->ratio;
899          hw->pcm_ops = audio_state.drv->pcm_ops;      swlim = audio_MIN (swlim, samples);
900          if (!hw->pcm_ops)      if (swlim) {
901              return NULL;          sw->conv (sw->buf, buf, swlim, &sw->vol);
902        }
903    
904          if (pcm_hw_init (hw, freq, nchannels, fmt)) {      while (swlim) {
905              pcm_hw_gc (hw);          dead = hwsamples - live;
906              return NULL;          left = hwsamples - wpos;
907            blck = audio_MIN (dead, left);
908            if (!blck) {
909                break;
910          }          }
911          else          isamp = swlim;
912              return hw;          osamp = blck;
913            st_rate_flow_mix (
914                sw->rate,
915                sw->buf + pos,
916                sw->hw->mix_buf + wpos,
917                &isamp,
918                &osamp
919                );
920            ret += isamp;
921            swlim -= isamp;
922            pos += isamp;
923            live += osamp;
924            wpos = (wpos + osamp) % hwsamples;
925            total += osamp;
926      }      }
927    
928      return pcm_hw_find_any (NULL);      sw->total_hw_samples_mixed += total;
929        sw->empty = sw->total_hw_samples_mixed == 0;
930    
931    #ifdef DEBUG_OUT
932        dolog (
933            "%s: write size %d ret %d total sw %d, hw %d\n",
934            sw->name,
935            size >> sw->info.shift,
936            ret,
937            sw->total_hw_samples_mixed,
938            sw->hw->total_samples_played
939            );
940    #endif
941    
942        return ret << sw->info.shift;
943  }  }
944    
945  int pcm_hw_add_sw (HWVoice *hw, SWVoice *sw)  #ifdef DEBUG_AUDIO
946    static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
947  {  {
948      SWVoice **pvoice = qemu_mallocz ((hw->nb_voices + 1) * sizeof (sw));      dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
949      if (!pvoice)             cap, info->bits, info->sign, info->freq, info->nchannels);
         return -1;  
   
     memcpy (pvoice, hw->pvoice, hw->nb_voices * sizeof (sw));  
     qemu_free (hw->pvoice);  
     hw->pvoice = pvoice;  
     hw->pvoice[hw->nb_voices++] = sw;  
     return 0;  
950  }  }
951    #endif
952    
953    #define DAC
954    #include "audio_template.h"
955    #undef DAC
956    #include "audio_template.h"
957    
958  int pcm_hw_del_sw (HWVoice *hw, SWVoice *sw)  int AUD_write (SWVoiceOut *sw, void *buf, int size)
959  {  {
960      int i, j;      int bytes;
     if (hw->nb_voices > 1) {  
         SWVoice **pvoice = qemu_mallocz ((hw->nb_voices - 1) * sizeof (sw));  
961    
962          if (!pvoice) {      if (!sw) {
963              dolog ("Can not maintain consistent state (not enough memory)\n");          /* XXX: Consider options */
964              return -1;          return size;
965          }      }
966    
967          for (i = 0, j = 0; i < hw->nb_voices; i++) {      if (!sw->hw->enabled) {
968              if (j >= hw->nb_voices - 1) {          dolog ("Writing to disabled voice %s\n", sw->name);
969                  dolog ("Can not maintain consistent state "          return 0;
                        "(invariant violated)\n");  
                 return -1;  
             }  
             if (hw->pvoice[i] != sw)  
                 pvoice[j++] = hw->pvoice[i];  
         }  
         qemu_free (hw->pvoice);  
         hw->pvoice = pvoice;  
         hw->nb_voices -= 1;  
970      }      }
971      else {  
972          qemu_free (hw->pvoice);      bytes = sw->hw->pcm_ops->write (sw, buf, size);
973          hw->pvoice = NULL;      return bytes;
974          hw->nb_voices = 0;  }
975    
976    int AUD_read (SWVoiceIn *sw, void *buf, int size)
977    {
978        int bytes;
979    
980        if (!sw) {
981            /* XXX: Consider options */
982            return size;
983      }      }
984      return 0;  
985        if (!sw->hw->enabled) {
986            dolog ("Reading from disabled voice %s\n", sw->name);
987            return 0;
988        }
989    
990        bytes = sw->hw->pcm_ops->read (sw, buf, size);
991        return bytes;
992  }  }
993    
994  SWVoice *pcm_create_voice_pair (int freq, int nchannels, audfmt_e fmt)  int AUD_get_buffer_size_out (SWVoiceOut *sw)
995  {  {
996      SWVoice *sw;      return sw->hw->bufsize;
997      HWVoice *hw;  }
998    
999      sw = qemu_mallocz (sizeof (*sw));  void AUD_set_active_out (SWVoiceOut *sw, int on)
1000      if (!sw)  {
1001          goto err1;      HWVoiceOut *hw;
1002    
1003      hw = pcm_hw_add (freq, nchannels, fmt);      if (!sw) {
1004      if (!hw)          return;
1005          goto err2;      }
1006    
1007      if (pcm_hw_add_sw (hw, sw))      hw = sw->hw;
1008          goto err3;      if (sw->active != on) {
1009            SWVoiceOut *temp_sw;
1010    
1011      if (pcm_sw_init (sw, hw, freq, nchannels, fmt))          if (on) {
1012          goto err4;              int total;
1013    
1014      return sw;              hw->pending_disable = 0;
1015                if (!hw->enabled) {
1016                    hw->enabled = 1;
1017                    hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
1018                }
1019    
1020                if (sw->empty) {
1021                    total = 0;
1022                }
1023            }
1024            else {
1025                if (hw->enabled) {
1026                    int nb_active = 0;
1027    
1028                    for (temp_sw = hw->sw_head.lh_first; temp_sw;
1029                         temp_sw = temp_sw->entries.le_next) {
1030                        nb_active += temp_sw->active != 0;
1031                    }
1032    
1033  err4:                  hw->pending_disable = nb_active == 1;
1034      pcm_hw_del_sw (hw, sw);              }
1035  err3:          }
1036      pcm_hw_gc (hw);          sw->active = on;
1037  err2:      }
     qemu_free (sw);  
 err1:  
     return NULL;  
1038  }  }
1039    
1040  SWVoice *AUD_open (SWVoice *sw, const char *name,  void AUD_set_active_in (SWVoiceIn *sw, int on)
                    int freq, int nchannels, audfmt_e fmt)  
1041  {  {
1042      if (!audio_state.drv) {      HWVoiceIn *hw;
         return NULL;  
     }  
1043    
1044      if (sw && freq == sw->freq && sw->nchannels == nchannels && sw->fmt == fmt) {      if (!sw) {
1045          return sw;          return;
1046      }      }
1047    
1048      if (sw) {      hw = sw->hw;
1049          ldebug ("Different format %s %d %d %d\n",      if (sw->active != on) {
1050                  name,          SWVoiceIn *temp_sw;
                 sw->freq == freq,  
                 sw->nchannels == nchannels,  
                 sw->fmt == fmt);  
     }  
1051    
1052      if (nchannels != 1 && nchannels != 2) {          if (on) {
1053          dolog ("Bogus channel count %d for voice %s\n", nchannels, name);              if (!hw->enabled) {
1054          return NULL;                  hw->enabled = 1;
1055      }                  hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
1056                }
1057                sw->total_hw_samples_acquired = hw->total_samples_captured;
1058            }
1059            else {
1060                if (hw->enabled) {
1061                    int nb_active = 0;
1062    
1063      if (!audio_state.fixed_format && sw) {                  for (temp_sw = hw->sw_head.lh_first; temp_sw;
1064          pcm_sw_fini (sw);                       temp_sw = temp_sw->entries.le_next) {
1065          pcm_hw_del_sw (sw->hw, sw);                      nb_active += temp_sw->active != 0;
1066          pcm_hw_gc (sw->hw);                  }
1067          if (sw->name) {  
1068              qemu_free (sw->name);                  if (nb_active == 1) {
1069              sw->name = NULL;                      hw->enabled = 0;
1070          }                      hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
1071          qemu_free (sw);                  }
         sw = NULL;  
     }  
   
     if (sw) {  
         HWVoice *hw = sw->hw;  
         if (!hw) {  
             dolog ("Internal logic error voice %s has no hardware store\n",  
                    name);  
             return sw;  
         }  
   
         if (pcm_sw_init (sw, hw, freq, nchannels, fmt)) {  
             pcm_sw_fini (sw);  
             pcm_hw_del_sw (hw, sw);  
             pcm_hw_gc (hw);  
             if (sw->name) {  
                 qemu_free (sw->name);  
                 sw->name = NULL;  
1072              }              }
             qemu_free (sw);  
             return NULL;  
1073          }          }
1074            sw->active = on;
1075      }      }
1076      else {  }
1077          sw = pcm_create_voice_pair (freq, nchannels, fmt);  
1078          if (!sw) {  static int audio_get_avail (SWVoiceIn *sw)
1079              dolog ("Failed to create voice %s\n", name);  {
1080              return NULL;      int live;
1081          }  
1082        if (!sw) {
1083            return 0;
1084      }      }
1085    
1086      if (sw->name) {      live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired;
1087          qemu_free (sw->name);      if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
1088          sw->name = NULL;          dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
1089            return 0;
1090      }      }
1091      sw->name = qemu_strdup (name);  
1092      return sw;      ldebug (
1093            "%s: get_avail live %d ret %lld\n",
1094            sw->name,
1095            live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift
1096            );
1097    
1098        return (((int64_t) live << 32) / sw->ratio) << sw->info.shift;
1099  }  }
1100    
1101  void AUD_close (SWVoice *sw)  static int audio_get_free (SWVoiceOut *sw)
1102  {  {
1103      if (!sw)      int live, dead;
         return;  
1104    
1105      pcm_sw_fini (sw);      if (!sw) {
1106      pcm_hw_del_sw (sw->hw, sw);          return 0;
     pcm_hw_gc (sw->hw);  
     if (sw->name) {  
         qemu_free (sw->name);  
         sw->name = NULL;  
1107      }      }
     qemu_free (sw);  
 }  
1108    
1109  int AUD_write (SWVoice *sw, void *buf, int size)      live = sw->total_hw_samples_mixed;
 {  
     int bytes;  
1110    
1111      if (!sw->hw->enabled)      if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) {
1112          dolog ("Writing to disabled voice %s\n", sw->name);          dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples);
1113      bytes = sw->hw->pcm_ops->write (sw, buf, size);      }
1114      return bytes;  
1115        dead = sw->hw->samples - live;
1116    
1117    #ifdef DEBUG_OUT
1118        dolog ("%s: get_free live %d dead %d ret %lld\n",
1119               sw->name,
1120               live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift);
1121    #endif
1122    
1123        return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift;
1124  }  }
1125    
1126  void AUD_run (void)  static void audio_run_out (void)
1127  {  {
1128      HWVoice *hw = NULL;      HWVoiceOut *hw = NULL;
1129        SWVoiceOut *sw;
1130    
1131      while ((hw = pcm_hw_find_any_active_enabled (hw))) {      while ((hw = audio_pcm_hw_find_any_active_enabled_out (hw))) {
1132          int i;          int played;
1133          if (hw->pending_disable && pcm_hw_get_live (hw) <= 0) {          int live, free, nb_live;
1134    
1135            live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
1136            if (!nb_live) {
1137                live = 0;
1138            }
1139            if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
1140                dolog ("live=%d hw->samples=%d\n", live, hw->samples);
1141            }
1142    
1143            if (hw->pending_disable && !nb_live) {
1144    #ifdef DEBUG_OUT
1145                dolog ("Disabling voice\n");
1146    #endif
1147              hw->enabled = 0;              hw->enabled = 0;
1148              hw->pcm_ops->ctl (hw, VOICE_DISABLE);              hw->pending_disable = 0;
1149              for (i = 0; i < hw->nb_voices; i++) {              hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
1150                  hw->pvoice[i]->live = 0;              continue;
1151                  /* hw->pvoice[i]->old_ticks = 0; */          }
1152    
1153            if (!live) {
1154                for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
1155                    if (sw->active) {
1156                        free = audio_get_free (sw);
1157                        if (free > 0) {
1158                            sw->callback.fn (sw->callback.opaque, free);
1159                        }
1160                    }
1161              }              }
1162              continue;              continue;
1163          }          }
1164    
1165          hw->pcm_ops->run (hw);          played = hw->pcm_ops->run_out (hw);
1166          assert (hw->rpos < hw->samples);          if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
1167          for (i = 0; i < hw->nb_voices; i++) {              dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
1168              SWVoice *sw = hw->pvoice[i];                     hw->rpos, hw->samples, played);
1169              if (!sw->active && !sw->live && sw->old_ticks) {              hw->rpos = 0;
1170                  int64_t delta = qemu_get_clock (vm_clock) - sw->old_ticks;          }
1171                  if (delta > audio_state.ticks_threshold) {  
1172                      ldebug ("resetting old_ticks for %s\n", sw->name);  #ifdef DEBUG_OUT
1173                      sw->old_ticks = 0;          dolog ("played = %d total %d\n", played, hw->total_samples_played);
1174    #endif
1175    
1176            if (played) {
1177                hw->ts_helper += played;
1178            }
1179    
1180            for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
1181            again:
1182                if (!sw->active && sw->empty) {
1183                    continue;
1184                }
1185    
1186                if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) {
1187                    dolog ("played=%d sw->total_hw_samples_mixed=%d\n",
1188                           played, sw->total_hw_samples_mixed);
1189                    played = sw->total_hw_samples_mixed;
1190                }
1191    
1192                sw->total_hw_samples_mixed -= played;
1193    
1194                if (!sw->total_hw_samples_mixed) {
1195                    sw->empty = 1;
1196    
1197                    if (!sw->active && !sw->callback.fn) {
1198                        SWVoiceOut *temp = sw->entries.le_next;
1199    
1200    #ifdef DEBUG_PLIVE
1201                        dolog ("Finishing with old voice\n");
1202    #endif
1203                        AUD_close_out (sw);
1204                        sw = temp;
1205                        if (sw) {
1206                            goto again;
1207                        }
1208                        else {
1209                            break;
1210                        }
1211                    }
1212                }
1213    
1214                if (sw->active) {
1215                    free = audio_get_free (sw);
1216                    if (free > 0) {
1217                        sw->callback.fn (sw->callback.opaque, free);
1218                  }                  }
1219              }              }
1220          }          }
1221      }      }
1222  }  }
1223    
1224  int AUD_get_free (SWVoice *sw)  static void audio_run_in (void)
1225  {  {
1226      int free;      HWVoiceIn *hw = NULL;
1227    
1228      if (!sw)      while ((hw = audio_pcm_hw_find_any_active_enabled_in (hw))) {
1229          return 4096;          SWVoiceIn *sw;
1230            int captured, min;
1231    
1232      free = ((sw->hw->samples - sw->live) << sw->hw->shift) * sw->ratio          captured = hw->pcm_ops->run_in (hw);
         / INT_MAX;  
1233    
1234      free &= ~sw->hw->align;          min = audio_pcm_hw_find_min_in (hw);
1235      if (!free) return 0;          hw->total_samples_captured += captured - min;
1236            hw->ts_helper += captured;
1237    
1238      return free;          for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
1239  }              sw->total_hw_samples_acquired -= min;
1240    
1241  int AUD_get_buffer_size (SWVoice *sw)              if (sw->active) {
1242  {                  int avail;
     return sw->hw->bufsize;  
 }  
1243    
1244  void AUD_adjust (SWVoice *sw, int bytes)                  avail = audio_get_avail (sw);
1245  {                  if (avail > 0) {
1246      if (!sw)                      sw->callback.fn (sw->callback.opaque, avail);
1247          return;                  }
1248      sw->old_ticks += (ticks_per_sec * (int64_t) bytes) / sw->bytes_per_second;              }
1249            }
1250        }
1251  }  }
1252    
1253  void AUD_reset (SWVoice *sw)  static struct audio_option audio_options[] = {
1254  {      /* DAC */
1255      sw->active = 0;      {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out,
1256      sw->old_ticks = 0;       "Use fixed settings for host DAC", NULL, 0},
 }  
1257    
1258  int AUD_calc_elapsed (SWVoice *sw)      {"DAC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out,
1259  {       "Frequency for fixed host DAC", NULL, 0},
     int64_t now, delta, bytes;  
     int dead, swlim;  
1260    
1261      if (!sw)      {"DAC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out,
1262          return 0;       "Format for fixed host DAC", NULL, 0},
1263    
1264      now = qemu_get_clock (vm_clock);      {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_out,
1265      delta = now - sw->old_ticks;       "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0},
     bytes = (delta * sw->bytes_per_second) / ticks_per_sec;  
     if (delta < 0) {  
         dolog ("whoops delta(<0)=%lld\n", delta);  
         return 0;  
     }  
1266    
1267      dead = sw->hw->samples - sw->live;      {"DAC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out,
1268      swlim = ((dead * (int64_t) INT_MAX) / sw->ratio);       "Number of voices for DAC", NULL, 0},
1269    
1270      if (bytes > swlim) {      /* ADC */
1271          return swlim;      {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &audio_state.fixed_settings_out,
1272      }       "Use fixed settings for host ADC", NULL, 0},
     else {  
         return bytes;  
     }  
 }  
1273    
1274  void AUD_enable (SWVoice *sw, int on)      {"ADC_FIXED_FREQ", AUD_OPT_INT, &audio_state.fixed_freq_out,
1275  {       "Frequency for fixed ADC", NULL, 0},
     int i;  
     HWVoice *hw;  
1276    
1277      if (!sw)      {"ADC_FIXED_FMT", AUD_OPT_FMT, &audio_state.fixed_fmt_out,
1278          return;       "Format for fixed ADC", NULL, 0},
1279    
1280      hw = sw->hw;      {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &audio_state.fixed_channels_in,
1281      if (on) {       "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0},
1282          if (!sw->live)  
1283              sw->wpos = sw->hw->rpos;      {"ADC_VOICES", AUD_OPT_INT, &audio_state.nb_hw_voices_out,
1284          if (!sw->old_ticks) {       "Number of voices for ADC", NULL, 0},
1285              sw->old_ticks = qemu_get_clock (vm_clock);  
1286        /* Misc */
1287        {"TIMER_PERIOD", AUD_OPT_INT, &audio_state.period.usec,
1288         "Timer period in microseconds (0 - try lowest possible)", NULL, 0},
1289    
1290        {"PLIVE", AUD_OPT_BOOL, &audio_state.plive,
1291         "(undocumented)", NULL, 0},
1292    
1293        {NULL, 0, NULL, NULL, NULL, 0}
1294    };
1295    
1296    void AUD_help (void)
1297    {
1298        size_t i;
1299    
1300        audio_process_options ("AUDIO", audio_options);
1301        for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1302            struct audio_driver *d = drvtab[i];
1303            if (d->options) {
1304                audio_process_options (d->name, d->options);
1305          }          }
1306      }      }
1307    
1308      if (sw->active != on) {      printf ("Audio options:\n");
1309          if (on) {      audio_print_options ("AUDIO", audio_options);
1310              hw->pending_disable = 0;      printf ("\n");
1311              if (!hw->enabled) {  
1312                  hw->enabled = 1;      printf ("Available drivers:\n");
1313                  for (i = 0; i < hw->nb_voices; i++) {  
1314                      ldebug ("resetting voice\n");      for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1315                      sw = hw->pvoice[i];          struct audio_driver *d = drvtab[i];
1316                      sw->old_ticks = qemu_get_clock (vm_clock);  
1317                  }          printf ("Name: %s\n", d->name);
1318                  hw->pcm_ops->ctl (hw, VOICE_ENABLE);          printf ("Description: %s\n", d->descr);
1319              }  
1320            switch (d->max_voices_out) {
1321            case 0:
1322                printf ("Does not support DAC\n");
1323                break;
1324            case 1:
1325                printf ("One DAC voice\n");
1326                break;
1327            case INT_MAX:
1328                printf ("Theoretically supports many DAC voices\n");
1329                break;
1330            default:
1331                printf ("Theoretically supports upto %d DAC voices\n",
1332                         d->max_voices_out);
1333                break;
1334          }          }
         else {  
             if (hw->enabled && !hw->pending_disable) {  
                 int nb_active = 0;  
                 for (i = 0; i < hw->nb_voices; i++) {  
                     nb_active += hw->pvoice[i]->active != 0;  
                 }  
1335    
1336                  if (nb_active == 1) {          switch (d->max_voices_in) {
1337                      hw->pending_disable = 1;          case 0:
1338                  }              printf ("Does not support ADC\n");
1339              }              break;
1340            case 1:
1341                printf ("One ADC voice\n");
1342                break;
1343            case INT_MAX:
1344                printf ("Theoretically supports many ADC voices\n");
1345                break;
1346            default:
1347                printf ("Theoretically supports upto %d ADC voices\n",
1348                         d->max_voices_in);
1349                break;
1350          }          }
1351          sw->active = on;  
1352            if (d->options) {
1353                printf ("Options:\n");
1354                audio_print_options (d->name, d->options);
1355            }
1356            else {
1357                printf ("No options\n");
1358            }
1359            printf ("\n");
1360      }      }
 }  
1361    
1362  static struct audio_output_driver *drvtab[] = {      printf (
1363  #ifdef CONFIG_OSS          "Options are settable through environment variables.\n"
1364      &oss_output_driver,          "Example:\n"
1365  #endif  #ifdef _WIN32
1366  #ifdef CONFIG_FMOD          "  set QEMU_AUDIO_DRV=wav\n"
1367      &fmod_output_driver,          "  set QEMU_WAV_PATH=c:/tune.wav\n"
1368  #endif  #else
1369  #ifdef CONFIG_SDL          "  export QEMU_AUDIO_DRV=wav\n"
1370      &sdl_output_driver,          "  export QEMU_WAV_PATH=$HOME/tune.wav\n"
1371  #endif          "(for csh replace export with setenv in the above)\n"
     &no_output_driver,  
 #ifdef USE_WAV_AUDIO  
     &wav_output_driver,  
1372  #endif  #endif
1373  };          "  qemu ...\n\n"
1374            );
1375    }
1376    
1377    void audio_timer (void *opaque)
1378    {
1379        AudioState *s = opaque;
1380    
1381        audio_run_out ();
1382        audio_run_in ();
1383    
1384        qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks);
1385    }
1386    
1387  static int voice_init (struct audio_output_driver *drv)  static int audio_driver_init (struct audio_driver *drv)
1388  {  {
1389        if (drv->options) {
1390            audio_process_options (drv->name, drv->options);
1391        }
1392      audio_state.opaque = drv->init ();      audio_state.opaque = drv->init ();
1393    
1394      if (audio_state.opaque) {      if (audio_state.opaque) {
1395          if (audio_state.nb_hw_voices > drv->max_voices) {          int i;
1396              dolog ("`%s' does not support %d multiple hardware channels\n"          HWVoiceOut *hwo;
1397                     "Resetting to %d\n",          HWVoiceIn *hwi;
1398                     drv->name, audio_state.nb_hw_voices, drv->max_voices);  
1399              audio_state.nb_hw_voices = drv->max_voices;          if (audio_state.nb_hw_voices_out > drv->max_voices_out) {
1400          }              if (!drv->max_voices_out) {
1401          hw_voices = qemu_mallocz (audio_state.nb_hw_voices * drv->voice_size);                  dolog ("`%s' does not support DAC\n", drv->name);
1402          if (hw_voices) {              }
1403              audio_state.drv = drv;              else {
1404              return 1;                  dolog (
1405                        "`%s' does not support %d multiple DAC voicess\n"
1406                        "Resetting to %d\n",
1407                        drv->name,
1408                        audio_state.nb_hw_voices_out,
1409                        drv->max_voices_out
1410                        );
1411                }
1412                audio_state.nb_hw_voices_out = drv->max_voices_out;
1413          }          }
1414          else {  
1415              dolog ("Not enough memory for %d `%s' voices (each %d bytes)\n",          LIST_INIT (&hw_head_out);
1416                     audio_state.nb_hw_voices, drv->name, drv->voice_size);          hwo = qemu_mallocz (audio_state.nb_hw_voices_out * drv->voice_size_out);
1417            if (!hwo) {
1418                dolog (
1419                    "Not enough memory for %d `%s' DAC voices (each %d bytes)\n",
1420                    audio_state.nb_hw_voices_out,
1421                    drv->name,
1422                    drv->voice_size_out
1423                    );
1424              drv->fini (audio_state.opaque);              drv->fini (audio_state.opaque);
1425              return 0;              return -1;
1426            }
1427    
1428            for (i = 0; i < audio_state.nb_hw_voices_out; ++i) {
1429                LIST_INSERT_HEAD (&hw_head_out, hwo, entries);
1430                hwo = advance (hwo, drv->voice_size_out);
1431            }
1432    
1433            if (!drv->voice_size_in && drv->max_voices_in) {
1434                ldebug ("warning: No ADC voice size defined for `%s'\n",
1435                        drv->name);
1436                drv->max_voices_in = 0;
1437          }          }
1438    
1439            if (!drv->voice_size_out && drv->max_voices_out) {
1440                ldebug ("warning: No DAC voice size defined for `%s'\n",
1441                        drv->name);
1442            }
1443    
1444            if (drv->voice_size_in && !drv->max_voices_in) {
1445                ldebug ("warning: ADC voice size is %d for ADC less driver `%s'\n",
1446                        drv->voice_size_out, drv->name);
1447            }
1448    
1449            if (drv->voice_size_out && !drv->max_voices_out) {
1450                ldebug ("warning: DAC voice size is %d for DAC less driver `%s'\n",
1451                        drv->voice_size_in, drv->name);
1452            }
1453    
1454            if (audio_state.nb_hw_voices_in > drv->max_voices_in) {
1455                if (!drv->max_voices_in) {
1456                    ldebug ("`%s' does not support ADC\n", drv->name);
1457                }
1458                else {
1459                    dolog (
1460                        "`%s' does not support %d multiple ADC voices\n"
1461                        "Resetting to %d\n",
1462                        drv->name,
1463                        audio_state.nb_hw_voices_in,
1464                        drv->max_voices_in
1465                        );
1466                }
1467                audio_state.nb_hw_voices_in = drv->max_voices_in;
1468            }
1469    
1470            LIST_INIT (&hw_head_in);
1471            hwi = qemu_mallocz (audio_state.nb_hw_voices_in * drv->voice_size_in);
1472            if (!hwi) {
1473                dolog (
1474                    "Not enough memory for %d `%s' ADC voices (each %d bytes)\n",
1475                    audio_state.nb_hw_voices_in,
1476                    drv->name,
1477                    drv->voice_size_in
1478                    );
1479                qemu_free (hwo);
1480                drv->fini (audio_state.opaque);
1481                return -1;
1482            }
1483    
1484            for (i = 0; i < audio_state.nb_hw_voices_in; ++i) {
1485                LIST_INSERT_HEAD (&hw_head_in, hwi, entries);
1486                hwi = advance (hwi, drv->voice_size_in);
1487            }
1488    
1489            audio_state.drv = drv;
1490            return 0;
1491      }      }
1492      else {      else {
1493          dolog ("Could not init `%s' audio\n", drv->name);          dolog ("Could not init `%s' audio driver\n", drv->name);
1494          return 0;          return -1;
1495      }      }
1496  }  }
1497    
1498  static void audio_vm_stop_handler (void *opaque, int reason)  static void audio_vm_stop_handler (void *opaque, int reason)
1499  {  {
1500      HWVoice *hw = NULL;      HWVoiceOut *hwo = NULL;
1501        HWVoiceIn *hwi = NULL;
1502        int op = reason ? VOICE_ENABLE : VOICE_DISABLE;
1503    
1504        (void) opaque;
1505        while ((hwo = audio_pcm_hw_find_any_out (hwo))) {
1506            if (!hwo->pcm_ops) {
1507                continue;
1508            }
1509    
1510            if (hwo->enabled != reason) {
1511                hwo->pcm_ops->ctl_out (hwo, op);
1512            }
1513        }
1514    
1515      while ((hw = pcm_hw_find_any (hw))) {      while ((hwi = audio_pcm_hw_find_any_in (hwi))) {
1516          if (!hw->pcm_ops)          if (!hwi->pcm_ops) {
1517              continue;              continue;
1518            }
1519    
1520          hw->pcm_ops->ctl (hw, reason ? VOICE_ENABLE : VOICE_DISABLE);          if (hwi->enabled != reason) {
1521                hwi->pcm_ops->ctl_in (hwi, op);
1522            }
1523      }      }
1524  }  }
1525    
1526  static void audio_atexit (void)  static void audio_atexit (void)
1527  {  {
1528      HWVoice *hw = NULL;      HWVoiceOut *hwo = NULL;
1529        HWVoiceIn *hwi = NULL;
1530    
1531        while ((hwo = audio_pcm_hw_find_any_out (hwo))) {
1532            if (!hwo->pcm_ops) {
1533                continue;
1534            }
1535    
1536      while ((hw = pcm_hw_find_any (hw))) {          if (hwo->enabled) {
1537          if (!hw->pcm_ops)              hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
1538            }
1539            hwo->pcm_ops->fini_out (hwo);
1540        }
1541    
1542        while ((hwi = audio_pcm_hw_find_any_in (hwi))) {
1543            if (!hwi->pcm_ops) {
1544              continue;              continue;
1545            }
1546    
1547          hw->pcm_ops->ctl (hw, VOICE_DISABLE);          if (hwi->enabled) {
1548          hw->pcm_ops->fini (hw);              hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
1549            }
1550            hwi->pcm_ops->fini_in (hwi);
1551      }      }
1552      audio_state.drv->fini (audio_state.opaque);      audio_state.drv->fini (audio_state.opaque);
1553  }  }
1554    
1555  static void audio_save (QEMUFile *f, void *opaque)  static void audio_save (QEMUFile *f, void *opaque)
1556  {  {
1557        (void) f;
1558        (void) opaque;
1559  }  }
1560    
1561  static int audio_load (QEMUFile *f, void *opaque, int version_id)  static int audio_load (QEMUFile *f, void *opaque, int version_id)
1562  {  {
1563      if (version_id != 1)      (void) f;
1564        (void) opaque;
1565    
1566        if (version_id != 1) {
1567          return -EINVAL;          return -EINVAL;
1568        }
1569    
1570      return 0;      return 0;
1571  }  }
1572    
1573  void AUD_init (void)  void AUD_init (void)
1574  {  {
1575      int i;      size_t i;
1576      int done = 0;      int done = 0;
1577      const char *drvname;      const char *drvname;
1578        AudioState *s = &audio_state;
1579    
1580      audio_state.fixed_format =      audio_process_options ("AUDIO", audio_options);
1581          !!audio_get_conf_int (QC_FIXED_FORMAT, audio_state.fixed_format);  
1582      audio_state.fixed_freq =      if (s->nb_hw_voices_out <= 0) {
1583          audio_get_conf_int (QC_FIXED_FREQ, audio_state.fixed_freq);          dolog ("Bogus number of DAC voices %d\n",
1584      audio_state.nb_hw_voices =                 s->nb_hw_voices_out);
1585          audio_get_conf_int (QC_VOICES, audio_state.nb_hw_voices);          s->nb_hw_voices_out = 1;
1586        }
1587      if (audio_state.nb_hw_voices <= 0) {  
1588          dolog ("Bogus number of voices %d, resetting to 1\n",      if (s->nb_hw_voices_in <= 0) {
1589                 audio_state.nb_hw_voices);          dolog ("Bogus number of ADC voices %d\n",
1590                   s->nb_hw_voices_in);
1591            s->nb_hw_voices_in = 1;
1592        }
1593    
1594        {
1595            int def;
1596            drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
1597        }
1598    
1599        s->ts = qemu_new_timer (vm_clock, audio_timer, s);
1600        if (!s->ts) {
1601            dolog ("Can not create audio timer\n");
1602            return;
1603      }      }
1604    
     drvname = audio_get_conf_str (QC_AUDIO_DRV, NULL);  
1605      if (drvname) {      if (drvname) {
1606          int found = 0;          int found = 0;
1607    
1608          for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {          for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1609              if (!strcmp (drvname, drvtab[i]->name)) {              if (!strcmp (drvname, drvtab[i]->name)) {
1610                  done = voice_init (drvtab[i]);                  done = !audio_driver_init (drvtab[i]);
1611                  found = 1;                  found = 1;
1612                  break;                  break;
1613              }              }
1614          }          }
1615    
1616          if (!found) {          if (!found) {
1617              dolog ("Unknown audio driver `%s'\n", drvname);              dolog ("Unknown audio driver `%s'\n", drvname);
1618                dolog ("Run with -audio-help to list available drivers\n");
1619          }          }
1620      }      }
1621    
# Line 895  void AUD_init (void) Line 1624  void AUD_init (void)
1624    
1625      if (!done) {      if (!done) {
1626          for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {          for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
1627              if (drvtab[i]->can_be_default)              if (drvtab[i]->can_be_default) {
1628                  done = voice_init (drvtab[i]);                  done = !audio_driver_init (drvtab[i]);
1629                }
1630          }          }
1631      }      }
1632    
     audio_state.ticks_threshold = ticks_per_sec / 50;  
     audio_state.freq_threshold = 100;  
   
1633      register_savevm ("audio", 0, 1, audio_save, audio_load, NULL);      register_savevm ("audio", 0, 1, audio_save, audio_load, NULL);
1634      if (!done) {      if (!done) {
1635          dolog ("Can not initialize audio subsystem\n");          if (audio_driver_init (&no_audio_driver)) {
1636          voice_init (&no_output_driver);              dolog ("Can not initialize audio subsystem\n");
1637            }
1638            else {
1639                dolog ("warning: using timer based audio emulation\n");
1640            }
1641      }      }
1642    
1643        if (s->period.usec <= 0) {
1644            if (s->period.usec < 0) {
1645                dolog ("warning: timer period is negative - %d treating as zero\n",
1646                       s->period.usec);
1647            }
1648            s->period.ticks = 1;
1649        }
1650        else {
1651            s->period.ticks = (ticks_per_sec * s->period.usec) / 1000000;
1652        }
1653    
1654        qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + s->period.ticks);
1655  }  }

Legend:
Removed from v.1.5  
changed lines
  Added in v.1.6

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