qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] audio output overflow when play movies


From: address@hidden
Subject: [Qemu-devel] audio output overflow when play movies
Date: Tue, 8 Mar 2016 16:31:17 +0800

Hi,
    I run Windows7, which plays HD Movies again and again, on QEMU emulator 2.0.1 for several days. then I found the main thread which invoke audio_pcm_sw_read->st_rate_flow get stuck.
    Is anyone ever notice it?

    here is the backtrace:
        Thread 1 (Thread 0x7f5e569dc920 (LWP 2683)):
    #0  st_rate_flow (opaque=0x7f5e5a83efd0, ibuf=0x7f5e5a0b8070, obuf=0x7f5e5acd11c0, address@hidden, address@hidden)
        at audio/rate_template.h:71
    #1  0x00007f5e56b95a16 in audio_pcm_sw_read (sw=0x7f5e59f9ca10, buf=0x7f5e59fa06d8, size=<optimized out>) at audio/audio.c:954
    #2  0x00007f5e56c0d0ee in hda_audio_input_cb (opaque=0x7f5e59fa0690, avail=2640) at hw/audio/hda-codec.c:187
    #3  0x00007f5e56b974ed in audio_run_in (s=<optimized out>) at audio/audio.c:1490
    #4  audio_run (address@hidden "timer") at audio/audio.c:1549
    #5  0x00007f5e56b97524 in audio_timer (opaque=0x7f5e573cfd20) at audio/audio.c:1137
    #6  0x00007f5e56d1adb9 in timerlist_run_timers (timer_list=0x7f5e597e83c0) at qemu-timer.c:493
    #7  0x00007f5e56d1ae8a in qemu_clock_run_timers (address@hidden) at qemu-timer.c:504
    #8  0x00007f5e56d1b2d8 in qemu_clock_run_all_timers () at qemu-timer.c:610
    #9  0x00007f5e56cdda4c in main_loop_wait (nonblocking=<optimized out>) at main-loop.c:515
    #10 0x00007f5e56b8e203 in main_loop () at vl.c:2360
    #11 main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4970
    
    with the follow code:    
    /*
     * Processed signed long samples from ibuf to obuf.
     * Return number of samples processed.
     */
    void st_rate_flow (void *opaque, struct st_sample *ibuf, struct st_sample *obuf,
               int *isamp, int *osamp)
    {
        struct rate *rate = opaque;
        struct st_sample *istart, *iend;
        struct st_sample *ostart, *oend;
        struct st_sample ilast, icur, out;
    #ifdef FLOAT_MIXENG
        mixeng_real t;
    #else
        int64_t t;
    #endif

        ilast = rate->ilast;

        istart = ibuf;
        iend = ibuf + *isamp;

        ostart = obuf;
        oend = obuf + *osamp;

        if (rate->opos_inc == (1ULL + UINT_MAX)) {
            int i, n = *isamp > *osamp ? *osamp : *isamp;
            for (i = 0; i < n; i++) {
                OP (obuf[i].l, ibuf[i].l);
                OP (obuf[i].r, ibuf[i].r);
            }
            *isamp = n;
            *osamp = n;
            return;
        }

        while (obuf < oend) {

            /* Safety catch to make sure we have input samples.  */
            if (ibuf >= iend) {
                break;
            }

            /* read as many input samples so that ipos > opos */

            while (rate->ipos <= (rate->opos >> 32)) { // P1: (rate->opos >> 32) = 0xFFFFFFFF
                ilast = *ibuf++;
                rate->ipos++;
                /* See if we finished the input buffer yet */
                if (ibuf >= iend) {
                    goto the_end; // P2: goto the end
                }
            }

            icur = *ibuf;

            /* interpolate */
    #ifdef FLOAT_MIXENG
    #ifdef RECIPROCAL
            t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX);
    #else
            t = (rate->opos & UINT_MAX) / (mixeng_real) UINT_MAX;
    #endif
            out.l = (ilast.l * (1.0 - t)) + icur.l * t;
            out.r = (ilast.r * (1.0 - t)) + icur.r * t;
    #else
            t = rate->opos & 0xffffffff;
            out.l = (ilast.l * ((int64_t) UINT_MAX - t) + icur.l * t) >> 32;
            out.r = (ilast.r * ((int64_t) UINT_MAX - t) + icur.r * t) >> 32;
    #endif

            /* output sample & increment position */
            OP (obuf->l, out.l);
            OP (obuf->r, out.r);
            obuf += 1;
            rate->opos += rate->opos_inc;
        }

    the_end: 
        *isamp = ibuf - istart;
        *osamp = obuf - ostart; // P3: osamp is 0 for obuf equal ostart
        rate->ilast = ilast;
    }

    int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size)
    {
        HWVoiceIn *hw = sw->hw;
        int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0;
        struct st_sample *src, *dst = sw->buf;

        rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples;

        live = hw->total_samples_captured - sw->total_hw_samples_acquired;
        if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) {
            dolog ("live_in=%d hw->samples=%d\n", live, hw->samples);
            return 0;
        }

        samples = size >> sw->info.shift;
        if (!live) {
            return 0;
        }

        swlim = (live * sw->ratio) >> 32;
        swlim = audio_MIN (swlim, samples);

        while (swlim) { // P5: come back again
            src = hw->conv_buf + rpos;
            isamp = hw->wpos - rpos;
            /* XXX: <= ? */
            if (isamp <= 0) {
                isamp = hw->samples - rpos;
            }

            if (!isamp) {
                break;
            }
            osamp = swlim;

            if (audio_bug (AUDIO_FUNC, osamp < 0)) {
                dolog ("osamp=%d\n", osamp);
                return 0;
            }

            st_rate_flow (sw->rate, src, dst, &isamp, &osamp);
            swlim -= osamp; // P4: nothing change when swlim substract 0
            rpos = (rpos + isamp) % hw->samples;
            dst += osamp;
            ret += osamp;
            total += isamp;
        }

        if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) {
            mixeng_volume (sw->buf, ret, &sw->vol);
        }

        sw->clip (buf, sw->buf, ret);
        sw->total_hw_samples_acquired += total;
        return ret << sw->info.shift;
    }


    #ANALYSIS:
    at position 1, P1:
    /* Private data */
struct rate {
uint64_t opos;
uint64_t opos_inc;
uint32_t ipos;                  /* position in the input stream (integer) */
struct st_sample ilast;          /* last sample in the input stream */
};

    while (rate->ipos <= (rate->opos >> 32)) { // P1: (rate->opos >> 32) = 0xFFFFFFFF
        ilast = *ibuf++;
        rate->ipos++;
        /* See if we finished the input buffer yet */
        if (ibuf >= iend) {
            goto the_end; // P2: goto the end
        }
    }
    
    I dump the value:
    (gdb) p *rate
    $45 = {opos = 18446744069687585005, opos_inc = 4674794335, ipos = 3649290292, ilast = {l = 0, r = 0}}
    
    as u can see, rate->opos = 18446744069687585005 = 0xFFFFFFFF1045A8ED, which higher part is 0xFFFFFFFF
    rate->ipos with uint32 type, which max value is 0xFFFFFFFF
    in the situation, (rate->ipos <= (rate->opos >> 32)) is definitely true forever.
    
    every time when the program break out at P2, go to P3, assign osamp to 0, return to audio_pcm_sw_read and swlim - 0 at P4, excute again at P5. so the main thread repeats the same flow again and again.
    
    the follow datas maybe useful:
    (gdb) p sw
$13 = (SWVoiceIn *) 0x7f5e59f9ca10
(gdb) p *sw
$14 = {card = 0x7f5e59fa0520, active = 1, info = {bits = 16, sign = 1, freq = 44100, nchannels = 2, align = 3, shift = 2, bytes_per_second = 176400, 
swap_endianness = 0}, ratio = 3946001203, rate = 0x7f5e5a83efd0, total_hw_samples_acquired = 70, buf = 0x7f5e5acd0e90, 
  clip = 0x7f5e56b98610 <clip_natural_int16_t_from_stereo>, hw = 0x7f5e5a15d1f0, name = 0x7f5e5a0f46c0 "adc", vol = {mute = 0, r = 4294967296, l = 4294967296}, 
  callback = {opaque = 0x7f5e59fa0690, fn = 0x7f5e56c0d080 <hda_audio_input_cb>}, entries = {le_next = 0x0, le_prev = 0x7f5e5a15d240}}

(gdb) p *hw
$32 = {enabled = 1, poll_mode = 0, info = {bits = 16, sign = 1, freq = 48000, nchannels = 2, align = 3, shift = 2, bytes_per_second = 192000, swap_endianness = 0}, 
  conv = 0x7f5e56b98540 <conv_natural_int16_t_to_stereo>, wpos = 736, total_samples_captured = 607, ts_helper = 4294967776, conv_buf = 0x7f5e5a0b68f0, 
  samples = 1920, sw_head = {lh_first = 0x7f5e59f9ca10}, ctl_caps = 8, pcm_ops = 0x7f5e5736eaa0, entries = {le_next = 0x0, le_prev = 0x7f5e573cfd40}}


    #TRIED
    1. I am not sure if this error occured just because I snapshotted the VM, but I really did 'snapshot operation' at that moment.
    
    2. If I change the value of rate->opos from 18446744069687585005 to 1, the program run just fine: 
    (gdb) p rate->opos
$47 = 18446744069687585005
(gdb) p rate->opos = 1
$48 = 1
    
    3. I calculated the value of opos/opos_inc = 18446744069687585005/4674794335 = 0xEB333333
    compared with the normal situation, opos/opos_inc = 17544193733109040684/3946001203 = 0x10901A124   
    (gdb) p *rate
    $2 = {opos = 17544193733109040684, opos_inc = 3946001203, ipos = 4084825920, ilast = {l = 57737216, r = 63569920}}
    maybe the opos_inc is incorrect.
    
    4. qemu argument with '-soundhw hda'
    
    5. the same phenomenon: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=685353

thanks!!!


address@hidden

reply via email to

[Prev in Thread] Current Thread [Next in Thread]