andrewrk / libsoundio

C library for cross-platform real-time audio input and output
http://libsound.io/
MIT License
1.94k stars 230 forks source link

Overflows in Parallels with ALSA #158

Open Timmmm opened 7 years ago

Timmmm commented 7 years ago

I'm recording from a sound device using ALSA in Parallels (not sure if that makes a difference). Anyway I'm getting overflow callbacks despite 100% definitely always reading the maximum number of samples available, with plenty of CPU to spare.

Here is the output of my program (explanation below):

Connecting to backend: default
ALSA lib setup.c:548:(add_elem) Cannot obtain info for CTL elem (MIXER,'IEC958 Playback Default',0,0,0): No such file or directory
ALSA lib pcm_dmix.c:968:(snd_pcm_dmix_open) The dmix plugin supports only playback stream
ALSA lib pcm_dmix.c:968:(snd_pcm_dmix_open) The dmix plugin supports only playback stream
ALSA lib pcm_dsnoop.c:545:(snd_pcm_dsnoop_open) The dsnoop plugin supports only capture stream
Duration: 36000
Device: Intel 82801BA-ICH2, Intel 82801BA-ICH2: Direct hardware device without any conversions not raw
Default format: 0 sample rate: 0
Opening with format: 3 sample rate: 48000
Stereo 48000 Hz signed 16-bit LE
0
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
1
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
2
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
3
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
4
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
5
Avail: 8192
Read, min: 0 max: 8192 actual: 8192
Avail: 8197
Read, min: 0 max: 8197 actual: 8197
Avail: 8194
Read, min: 0 max: 8194 actual: 8194
Avail: 8229
Read, min: 0 max: 8229 actual: 8229
Avail: 8197
Read, min: 0 max: 8197 actual: 8197
6
Avail: 16356
Read, min: 0 max: 16356 actual: 16356
Avail: 8231
Read, min: 0 max: 8231 actual: 8231
Avail: 16324
Read, min: 0 max: 16324 actual: 16324
Avail: 8240
Read, min: 0 max: 8240 actual: 8240
7
Avail: 16381
Read, min: 0 max: 16381 actual: 16381
Avail: 16360
Read, min: 0 max: 16360 actual: 16360
Avail: 8196
Read, min: 0 max: 8196 actual: 8196
Avail: 8223
Read, min: 0 max: 8223 actual: 8223
8
Avail: 8193
Read, min: 0 max: 8193 actual: 8193
Avail: 8196
Read, min: 0 max: 8196 actual: 8196
Avail: 8193
Read, min: 0 max: 8193 actual: 8193
Avail: 16354
Read, min: 0 max: 16354 actual: 16354
Avail: 8205
Read, min: 0 max: 8205 actual: 8205
9
Avail: 16353
Read, min: 0 max: 16353 actual: 16353
Avail: 8227
Read, min: 0 max: 8227 actual: 8227
Avail: 16342
Read, min: 0 max: 16342 actual: 16342
Avail: 8208
Read, min: 0 max: 8208 actual: 8208
10

I'm not sure what is going on with the ALSA errors at the top. In the main chunk of output, the lone integers 1..10 are just the number of seconds that have passed. The Read, min: 0, max: 8192, actual: 8192 lines are in the read callback, printing the minimum, maximum and actual number of samples read. I have a 30 second ring buffer so can easily always read the maximum. Avail: xxx is something I added to alsa.c here:

                snd_pcm_sframes_t avail = snd_pcm_avail_update(isa->handle);

                printf("Avail: %ld\n", avail);

                if (avail < 0) {
                    if ((err = instream_xrun_recovery(is, avail)) < 0) {
                        instream->error_callback(instream, SoundIoErrorStreaming);
                        return;
                    }
                    continue;
                }

At the end of the above output avail is equal to -32 (-EPIPE). I'm not sure why it doesn't print Avail: -32 but whatever. This means it calls instream_xrun_recovery(is, -32) which is as follows:

static int instream_xrun_recovery(struct SoundIoInStreamPrivate *is, int err) {
    struct SoundIoInStream *instream = &is->pub;
    struct SoundIoInStreamAlsa *isa = &is->backend_data.alsa;
    if (err == -EPIPE) {
        err = snd_pcm_prepare(isa->handle);
        if (err >= 0)
            instream->overflow_callback(instream);
    } else if (err == -ESTRPIPE) {
        while ((err = snd_pcm_resume(isa->handle)) == -EAGAIN) {
            // wait until suspend flag is released
            poll(NULL, 0, 1);
        }
        if (err < 0)
            err = snd_pcm_prepare(isa->handle);
        if (err >= 0)
            instream->overflow_callback(instream);
    }
    return err;
}

In that function it calls snd_pcm_prepare() which returns 0, and hence calls my overflow callback. The thing is, the documentation for snd_pcm_prepare() say 0 means success.

Can you confirm that this code is correct? And do you have any idea why it is overflowing? These are the details for the device I was trying to use (at 48 kHz stereo LE16).

Intel 82801BA-ICH2, Intel 82801BA-ICH2: Direct hardware device without any conversions
  id: hw:CARD=I82801BAICH2,DEV=0
  channel layouts:
    Stereo

  sample rates:
    8000 - 48000
  formats: signed 16-bit LE
  min software latency: 0.000166667
  max software latency: 0.341333

As I said this is running through Parallels, which I know does funky things with isochronous USB. Maybe it does similar crazy things with on-board sound cards. Still I feel like I shouldn't be getting overflows.