Oboe: A C++ library for low latency audio in Android
android-developers.googleblog.com
android-developers.googleblog.com
The "lowest possible" on android might not be low enough for musical instuments (<10-15ms). It's revealing that they don't reveal latency for any devices at all. (If I sound cynical, this isn't the first low-latency offering for android.) It's just "low" for android.
funfact: consoles also have terrible audio latency. Rhythm games like rockband/guitar hero don't actually need this, they need only relate it to the audio playing (and also config compensation for input latency). The latency is shocking if you use the mode where you free-"play" the instrument, and is why actual musicians often a tough time with these games. The surprising thing is that delayed sound effects from games in general aren't so jarring.
FWIW iphone audio latency also isn't good enough, despite being far better than android. That's how bad android is.
EDIT 7ms claimed in screenshot at https://github.com/google/oboe/blob/master/samples/hello-obo... - doesn't include input latency: average latency of the audio stream between data entering the stream and it being presented to the audio device
EDIT they know they need latency figures "Publish a list of Android device latency" https://github.com/google/oboe/issues/235
That's probably because talking about "the latency" for Android varies with actual hardware capability. It's like talking about "the latency" for Windows and Linux and forgetting that it's very bound to the actual hardware lying underneath. There are Android devices that achieve your desired level of latency, but obviously they're rather high-end and new.
Btw if you're looking for a subjective number for tolerable latency I'd say ~5ms. This could be output latency if you're playing notes via midi or round-trip latency if you're processing incoming sound and output it again. In my experience you don't get that acceptable latency on notebooks with the onboard sound cards either :)
but they don't play Bach on pipe organs with a drummer
So let's say that you are playing a simple three-note chord. Optimally, MIDI encodes this as a single status byte followed by three note+velocity pairs of data bytes. Just that is going to make something that should be instantaneous take 2.24 ms. Now add some CC messages, maybe a couple more channels, sync bytes etc. concentrated around rhythmic subdivisions and it's easily going to add up to 5-10 ms latency. And not just fixed latency, but jitter since the messages of course come in at different times.
Then, if you use a computer running Windows/Linux/OSX, you should probably account for MIDI driver latency and jitter as well. Maybe you are running a couple of instruments chained, at which point you'll also have to account for the latency between the input and the through output.
I easily hit the threshold where it's not only perceptible for the player but for a casual listener as well, but it's hard to say that it isn't "tolerable" when so much music has successfully been played and recorded with these limitations. Seems weird though that the industry has settled on this 80s protocol built for 80s machines. There's OSC (which is quite underspecified for the problem MIDI intends to address), some individual efforts by manufacturers (e.g. Turbo MIDI by Elektron) and recently talks of a "MIDI HD" protocol. I hope something happens soon that all manufacturers can hop on board.
Totally agree about the limitations of MIDI, but it was conceived when I think the only alternative was the Roland DCB which would was even more limited and would cost a fortune in connectors. Today I would use "something" over Ethernet phy: open, very cheap, very fast and near realtime.
Well, it still adds up as far as you use the individual ports. If have a single keyboard controller with modulation and pitch bend wheels connected to one port I don't think it's far fetched to say that the latency of the MIDI messages for some instant action can add up to >5 ms on its own. Might be hard to notice, but that's my point! At that latency you might as well be discussing how close you should sit to the speakers. If you're 1.72 m from your speakers, that adds +5 ms latency. I'll reach that distance if I stand up playing with a stage monitor at my toes.
That said, I think that 5 ms here and there does matter. For example, 5 ms vs 10 ms audio buffers on a PC felt like night and day to me. The total time from finger to ear was probably already twice that, but it seems that shortening the audio buffer crossed some threshold where it suddenly didn't feel like I needed to adjust my playing for the latency.
I agree that Ethernet would have made sense today, and I think that some manufacturers already support something like that.
A decade after iOS, I guess it comes in from the "better late than never department", but I am happy. Apple seems to have lost its focus on the creative usage of their devices, and it has somewhat stagnated (compared to the initial explosion), plus iOS apps tend to be pricey.
Apple's decision to not include the headphone jack effectively puts the kibosh on their realtime audio / musicmaking apps. The latency on AirPods is atrocious. You press a key on a virtual keyboard, and count to three before you hear a sound.
Yes, this is probably solved by a dongle. Eh, I'd rather carry my Yamaha Reface DX around than think about that -- and the developers are going to have a FunTime(tm) explaining this to the users. (The sole reason musicians love iDevices so much is the JustWorks(tm) aspect - well, that just went out the window).
This Android API just might start a new wave. The video appeals to the synth nerd in me. The gear, the T-Shirt, the code samples doing the right thing.
I am looking forward to what this will bring us.
https://raphlinus.github.io/personal/2018/08/28/a-new-advent...
I agree that not having a headphone jack combined with the unacceptable latency of bluetooth makes it unusable for on-the-go music making.
As for pricing, I think that won't change on Android. Music making is a niche market, and these apps are not cheap to develop.
I hate to go there but I think the other factor is standardized hardware. You're guaranteed certain hardware setups for iOS devices, for Android it's anybody's guess really whether a phone can support some features or not. It would be nice if all Android phones had USB C, of course it would of been nicer if USB C had better regulation since now all USB C interfaces are like... Ah well a guy can dream can't he.
https://www.engadget.com/2018/06/05/live-listen-ios-12-apple...
When using this mode to listen to my TV, I can just tell that there is a delay between the real sound and those from the AirPods but it's not long enough a delay that I can't understand the speech or really bothers me.
If anyone has technical info I'd love to know. As I have also witnessed that in normal application you easily have 1-2 seconds of latency. Obviously videos synchronize with it but it's not ideal for games etc.
I do wonder if it's a matter of some settings the apps need to potentially set or some such. If you think about it calls are also lower latency than this .. though they use a different BT audio profile (HFP/HSP) that is mono instead of the A2DP Stereo Protocol.
Last of all I was surprised Apple didn't come up with some custom protocol mode for AirPods that allows Stereo+Mic. Gaming consoles do this on 2.4GHz even with multiple controllers so it seems possible in theory (though perhaps maybe not alongside 2.4GHz WiFi? not sure).
Would love more insight on all the above.
EDIT: Side note to the OP, just use a lightning adapter :-)
That absolutely destroys it for music apps. A decent latency for music apps is under 10ms. You don't hear it, you feel it when you press a key and you don't hear the sound immediately. It prevents you from playing fast, even if you kind of adjust to it.
Your brain is very sensitive to timing differences. Hit a drum with two sticks - you can hear the difference on beat and almost-on-beat very easily. And if you are trying to use vocal effects and hear your own voice delayed - that just messes with your brain.
Read this article for more background on how latency affects musicians and what number are acceptable: https://www.churchproduction.com/education/latency-and-its-a...
As for the side note - I played with my friend's iPhone, and decided to stay away from that device :) I still have an old iPod Touch which runs a looper just fine.
Touch screens, on the other hand, are a problem -- they add input latency if you want to use the screen as an instrument/controller, and that's what a lot of music apps do (virtual keyboards/drum pads/etc).
Last time I really tried those, every single device was atrocious in that respect (both iDevices and Android)[1] -- keep in mind that total latency from touch to sound should be under 10 ms to be really acceptable.
And things haven't been getting better until recently. Short of music equipment, the trend for everything has been to get more sluggish[2]
Razer Phone and iPhone X might change that[3] if others follow suit, so I'm hopeful (both feature 1/120sec touch latency, which is OK).
[1]https://www.imore.com/iphone-5-touchscreen-latency-measured-...
[2]https://danluu.com/input-lag/
[3]https://www.macworld.com/article/3235709/iphone-ipad/iphone-...
And maybe if they have enough buffer on their 20% we get some of the reported issues fixed.
Like cdep, Play Services for C++, FPL libraries...
If you are curious about latency, check out my android app "Hexpress" (on play store) that gives you drums and other instruments to play with. I measured roughly 50 ms of tap-to-sound delay, not consistent across devices. That lands it within 'cute audio toy' territory, which is why I stopped investing time.
AudioStream *AudioStreamBuilder::build() {
AudioStream *stream = nullptr;
if (mAudioApi == AudioApi::AAudio && isAAudioSupported()) {
stream = new AudioStreamAAudio(*this);
// If unspecified, only use AAudio if recommended.
} else if (mAudioApi == AudioApi::Unspecified && isAAudioRecommended()) {
stream = new AudioStreamAAudio(*this);
} else {
if (getDirection() == oboe::Direction::Output) {
stream = new AudioOutputStreamOpenSLES(*this);
} else if (getDirection() == oboe::Direction::Input) {
stream = new AudioInputStreamOpenSLES(*this);
}
}
return stream;
}
Result AudioStreamBuilder::openStream(AudioStream **streamPP) {
if (streamPP == nullptr) {
return Result::ErrorNull;
}
*streamPP = nullptr;
AudioStream *streamP = build();
if (streamP == nullptr) {
return Result::ErrorNull;
}
Result result = streamP->open(); // TODO review API
if (result == Result::OK) {
*streamPP = streamP;
}
return result;
}
Doesn't this leak memory if streamP->open() fails? I'm also surprised they are using new instead of unique_ptr, especially since one of their listed benefits is "Convenient C++ API (uses the C++11 standard) ".And this in modern C++ in year 2018:
if (result != Result::OK) { goto error2; }
Android Studio has also finally improved NDK support enough that writing large chunks of your app in C++ isn't painful anymore.
Sadly no OEM ever cared to my knowledge to integrate this work in their ROMs. I also openened an issue on the android bugtracker to feature request replacing audioflinger with alsa/pulseaudio. They never answered nor closed the issue but I haven't checked since 2 years.
Edit: here is the android feature request https://issuetracker.google.com/issues/37073168 Maybe if you comment/upvote it it may gain traction.
Digression: If you are interested in audio latency, I recall that Firefox has better webaudio performance than Chrome.
AudioStreamBuilder builder;
AudioStream *stream = nullptr;
Result result = builder.openStream(&stream);
Why even bother initializing stream to nullptr if it's going to be overwritten anyways by AudioStreamBuilder::openStream?Just in case, for example, the initialization gets moved inside of an if statement and no one thinks about the else case.
It's also just good practice to initialize your variables.
On Android devices (and smartphones in general) - hardware would be the limiting factor.
It just takes a SCHED_FIFO task with forced CPU affinity. Android does not make it easy to get one.
There are some other hardware issues, like audio input and output using separate clocks on Qualcomms, but that's at most one extra buffer.
Speaking of this, you can have sub-millisecond latencies on Beagleboard. These devices in phones are vastly more powerful.
The real time audio APIs are in native code and they can request for priority use when on foreground.
Samsung used to support real time audio on their S models since many years.
https://developer.samsung.com/galaxy/professional-audio
Which they are now deprecating as they also contributed to the design of AAudio.
People rightfully pointed out that tablets are plenty powerful to do DSP type applications, but something is consuming all the resources. I'm just saying what that something is.
I lost count the amount of times I have fixed junior code doing what should be background stuff written on the main thread, for loops instead of System.arraycopy, allocating memory in loops and lots of other stuff due to lack of proper teaching.
As for Android, the real time audio stack is fully native and Google had to learn from Samsung how to do it properly.
Are you aware of any non-RTOS that "makes it easy to get one"?
> "Speaking of this, you can have sub-millisecond latencies on Beagleboard."
I did not make myself clear, so I'm taking the blame here.
I'm mostly interested in the use case. If it's just capturing audio alone, this number makes sense, and no fancy hardware is necessary.
The moment we're introducing some-kind of processing, or even logging the stream to disc, buffering becomes necessary and latency is introduced. Assume audio stream read by a "user-mode" service, then redirected out through headphones - are we still talking sub-millisecond latencies?
[1]: http://bela.io
The problem on some platforms is one of architectural choices and prioritization. On Android we know they started with the already arguably poor latency Linux audio foundation of ASLA, then layered on and layered on (flingers and HLAs and user-mode transitions), each layer adding its own ring buffers.
Even on Windows, on the fastest PC known to man, audio has generally poor latency (because it's architectural) which is why audio software makers have their own hardware->application drivers (ASIO).
Low latency audio was not important to the project, and they dug themselves in so deep that for many years we've been hearing recurring "We've finally solved that latency issue" claims.
If you're programming in Rust, you can use the cpal crate, which wraps all these. I'm not sure cpal has astonishingly good performance in all cases, but I plan to work with the authors. It doesn't have an Android back-end yet, but such a thing should be possible.
If you use JUCE (https://juce.com/) you'll get a single API for all the different audio APIs on macOS, Windows, iOS, Android, Linux, etc.