PaulStoffregen / Audio

Teensy Audio Library
http://www.pjrc.com/teensy/td_libs_Audio.html
1.08k stars 401 forks source link

AudioPlayQueue stalls internally #415

Closed h4yn0nnym0u5e closed 1 year ago

h4yn0nnym0u5e commented 2 years ago

Description

AudioPlayQueue::getBuffer() and ::playBuffer() can stall internally, dramatically impacting user code throughput. Teensyduino 1.56 beta 3 has a new ::play() function, which uses both these functions, and thus suffers the same issue.

This behaviour is undocumented, and appears to be hard (impossible?) to work around in the user's application.

Steps To Reproduce Problem

Run the example sketch, and note that loop() iterates very slowly.

Hardware & Software

Board: any Shields / modules used: any Arduino IDE version: any Teensyduino version: 1.56 beta 3 Operating system & version: any Any other software or hardware?: no

Arduino Sketch

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioPlayQueue           queue1;         //xy=917,329
AudioOutputI2S           i2s2;           //xy=1121,330
AudioConnection          patchCord1(queue1, 0, i2s2, 0);
AudioConnection          patchCord2(queue1, 0, i2s2, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=1131,379
// GUItool: end automatically generated code

uint32_t next;
void setup() {
  pinMode(13,OUTPUT);

  Serial.begin(115200);
  while (!Serial)
    ;

  if (CrashReport) 
  {
    Serial.println(CrashReport);
    CrashReport.clear();
  }

  AudioMemory(10);

  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);

  next = millis();
}

int loops;
int nulls;
float phas;
void loop() {
  int16_t* buf = queue1.getBuffer();

  if (NULL == buf)
    nulls++;
  else
  {
    for (int i=0;i<AUDIO_BLOCK_SAMPLES;i++)
    {
      buf[i] = (int16_t) (sin(phas)*8000.);
      phas += 220./AUDIO_SAMPLE_RATE_EXACT*TWO_PI;
      if (phas > TWO_PI)
        phas -= TWO_PI;
    }
    queue1.playBuffer();
  }

  loops++;
  if (millis() > next)
  {
    next += 100;
    Serial.printf("millis = %d, loops = %d, nulls = %d\n",millis(),loops,nulls);
  }
}

Errors or Incorrect Output

Program output from running on Teensy 4.1. Note that we achieve about 345 iterations of loop() per second, because NULL is never returned from getBuffer()

millis = 736, loops = 2, nulls = 0 millis = 837, loops = 44, nulls = 0 millis = 936, loops = 78, nulls = 0 millis = 1037, loops = 113, nulls = 0 millis = 1136, loops = 147, nulls = 0 millis = 1237, loops = 182, nulls = 0 millis = 1336, loops = 216, nulls = 0 millis = 1438, loops = 251, nulls = 0 millis = 1536, loops = 285, nulls = 0 millis = 1638, loops = 320, nulls = 0 millis = 1737, loops = 354, nulls = 0 millis = 1838, loops = 389, nulls = 0 millis = 1937, loops = 423, nulls = 0 millis = 2036, loops = 457, nulls = 0 millis = 2137, loops = 492, nulls = 0 millis = 2236, loops = 526, nulls = 0 millis = 2338, loops = 561, nulls = 0 millis = 2436, loops = 595, nulls = 0 millis = 2538, loops = 630, nulls = 0 millis = 2636, loops = 664, nulls = 0 millis = 2738, loops = 699, nulls = 0 millis = 2837, loops = 733, nulls = 0

h4yn0nnym0u5e commented 1 year ago

Fixed by PR #417, which has been merged. But see PR #459 - demo is broken.