oboe icon indicating copy to clipboard operation
oboe copied to clipboard

Adjust OpenSL ES buffer queue length based on capacity

Open philburk opened this issue 5 years ago • 7 comments

Change kBufferQueueLength constant to mBufferQueueLength variable. Set mBufferQueueLength based on capacity and callbacksize.

See experiment on the effect of kBufferQueueLength on latency in: Why Oboe only enqueue one buffer? #464

Understanding FramesPerCallback / kBufferQueueLength / Buffer Size #736

According to this internal bug:

b/27819623 | Allow OpenSL ES to specify a total buffer size for a fast track

starting in N, adding more buffers would improve glitch protection. So this change would help devices running 7.0, 7.1 and 8.0. That would be about 1/3 of Android devices. For 8.1 and later, AAudio is available.

[Update: as of August 2022, 17.5% of devices are running < 8.1]

philburk avatar Dec 29 '19 22:12 philburk

Allow OpenSL ES to specify a total buffer size for a fast track Has this feature implemented in branch 1.3-stable?

klw111 avatar Mar 24 '20 12:03 klw111

No. This issue is still open.

philburk avatar Mar 29 '20 18:03 philburk

Measure the effect of changing kBufferQueueLength on Sargo running SP2A with OpenSL ES with Low Latency. Burst = 192.

kBufferQueueLength RT latency Capacity
2 22.2
3 24.1 576
4 25.9 768

Latency increases by 2 msec (96 frames) per buffer. Not 192!

Used main Oboetester screen to set frames per callback to 96.

kBufferQueueLength RT latency Capacity
2 17.8 192
3 19.9 288
4 22.2 384

The latency still increases by 2 msec/buffer but the latency is lower!

I then set kBufferQueueLength and added some code to the beginning of processBufferCallback(). Burst = 192. if (getBufferDepth(bq) >= 3) { return false; }

maxDepth RT latency Capacity
3 34.2 1536
4 34.0 1536
5 34.27 1536

This does not seem to affect latency! I expected it to limit the amount of data in the buffer. I added some logs and the depth was always zero.

philburk avatar Aug 06 '22 00:08 philburk

I then added a loop in processBufferCallback:

while (depth < 4 && countdown-- > 0 && !shouldStopStream) {

In the first callback I could see the depth grow to four then stabilize.

maxDepth RT latency Capacity
1 34.4 1536
2 37.8 1536
3 42.2 1536
4 45.8 1536
5 50.6 1536
6 54.3 1536
7 58.0 1536
8 62.3 1536

At 9 it failed to start because there were only 8 buffers allocated.

philburk avatar Aug 06 '22 00:08 philburk

Hypothesis: in Android S the kBufferQueueLength affects the size of the internal buffer, which increases latency and should afford some glitch protection. Enqueuing multiple buffers increases the queue depth, adds latency. But I suspect these buffers are stored on the client side and will not help with glitch protection.

philburk avatar Aug 06 '22 16:08 philburk

Testing on a Nexus 6 running SDK 6.0.1, burst = 192. Use format = PCM_I16 for input and output, analog headset jack.

kBufferQueueLength RT latency Capacity
2 50.0 384
3 49.5 576
4 49.7 768

Latency, and glitch protection, does not increase with the number of buffers. That was added in 7.0. ag/941250 SDK 6.0 has problems that we cannot fix in Oboe.

philburk avatar Aug 08 '22 18:08 philburk

Testing on a Nexus 6 running SDK 7 MR2, burst = 192. Use format = PCM_I16 for input and output, analog headset jack.

kBufferQueueLength RT latency Capacity
2 53.3 384
3 57.5 576
4 61.5 768

Latency, and glitch protection, increases with the number of buffers.

philburk avatar Aug 08 '22 18:08 philburk