-
Notifications
You must be signed in to change notification settings - Fork 0
Android native: tighten Oboe build, fix getLastError race, cut audio-thread syscalls #208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -114,7 +114,7 @@ bool OboeBridge::open(int32_t sampleRate) { | |||||||
| // Audio is pre-mixed by BASS — tell Android not to spatialize it again. | ||||||||
| ->setIsContentSpatialized(true) | ||||||||
| // Prevent other apps from capturing our audio stream (competitive integrity). | ||||||||
| ->setAllowedCapturePolicy(oboe::AllowedCapturePolicy::AllowNone) | ||||||||
| ->setAllowedCapturePolicy(oboe::AllowedCapturePolicy::None) | ||||||||
| // Use shared_ptr overload (non-deprecated) for data callback. | ||||||||
| ->setDataCallback(stabilizedCallback_) | ||||||||
| // Non-owning shared_ptr for error callback — OboeBridge outlives the stream. | ||||||||
|
|
@@ -250,9 +250,9 @@ void OboeBridge::setProvider(OboeAudioProvider provider) { | |||||||
| provider_.store(provider, std::memory_order_release); | ||||||||
| } | ||||||||
|
|
||||||||
| const char* OboeBridge::getLastError() const { | ||||||||
| std::string OboeBridge::getLastError() const { | ||||||||
| std::lock_guard<std::mutex> lock(errorLock_); | ||||||||
| return lastError_.empty() ? nullptr : lastError_.c_str(); | ||||||||
| return lastError_; | ||||||||
| } | ||||||||
|
|
||||||||
| oboe::DataCallbackResult OboeBridge::onAudioReady( | ||||||||
|
|
@@ -283,14 +283,19 @@ oboe::DataCallbackResult OboeBridge::onAudioReady( | |||||||
|
|
||||||||
| uint32_t count = callbackCount_.fetch_add(1, std::memory_order_relaxed); | ||||||||
|
|
||||||||
| // LatencyTuner once every 128 callbacks (~1.5s @ 192 burst, 48 kHz). | ||||||||
| // updateLatency() issues an AAudio syscall, so throttle it further to every | ||||||||
| // 256 callbacks — Tab still sees stable values, but we cut audio-thread | ||||||||
| // syscall pressure in half. | ||||||||
| if ((count & 127) == 0) { | ||||||||
| updateLatency(); | ||||||||
|
|
||||||||
| // Dynamically tune the buffer size to the lowest stable value. | ||||||||
| if (tuner_) { | ||||||||
| tuner_->tune(); | ||||||||
| } | ||||||||
|
|
||||||||
| if ((count & 255) == 0) | ||||||||
| updateLatency(); | ||||||||
|
|
||||||||
| // Attempt to set CPU affinity to high-performance cores. | ||||||||
| // We do this inside the audio callback to ensure we target the AAudio thread. | ||||||||
| // Uses sysfs-based topology detection for accurate big-core identification | ||||||||
|
|
@@ -478,7 +483,15 @@ OSU_EXPORT void nOboeSetProvider(intptr_t ptr, OboeAudioProvider provider) { | |||||||
|
|
||||||||
| OSU_EXPORT const char* nOboeGetLastErrorMessage(intptr_t ptr) { | ||||||||
| auto* bridge = reinterpret_cast<OboeBridge*>(ptr); | ||||||||
| return bridge ? bridge->getLastError() : nullptr; | ||||||||
| if (!bridge) return nullptr; | ||||||||
|
|
||||||||
| // Hold a thread_local snapshot so the pointer we hand back to managed code | ||||||||
| // remains valid for the duration of the P/Invoke marshalling step, even if | ||||||||
| // another thread (Oboe error callback) overwrites `lastError_` immediately | ||||||||
| // after we return. Each managed thread gets its own buffer. | ||||||||
| thread_local std::string snapshot; | ||||||||
| snapshot = bridge->getLastError(); | ||||||||
| return snapshot.empty() ? nullptr : snapshot.c_str(); | ||||||||
| } | ||||||||
|
|
||||||||
| } // extern "C" | ||||||||
|
|
@@ -512,6 +525,9 @@ OSU_EXPORT int nGetBigCoreMask() { | |||||||
| } | ||||||||
|
|
||||||||
| #include <android/performance_hint.h> | ||||||||
| // Explicit dependency for gettid() used in nADPFCreateSession below — do not | ||||||||
| // rely on transitive includes from Oboe / NDK headers, which may change. | ||||||||
| #include <unistd.h> | ||||||||
|
Comment on lines
+528
to
+530
|
||||||||
| // Explicit dependency for gettid() used in nADPFCreateSession below — do not | |
| // rely on transitive includes from Oboe / NDK headers, which may change. | |
| #include <unistd.h> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,7 +33,11 @@ class OboeBridge : public oboe::AudioStreamCallback { | |
| bool isAAudio() const; | ||
| bool isMMap() const; | ||
| void setProvider(OboeAudioProvider provider); | ||
| const char* getLastError() const; | ||
| /// Returns a copy of the most recent error message under lock. We return | ||
| /// by value (not a pointer to internal storage) so callers can't observe a | ||
| /// torn or freed `std::string` if another thread mutates `lastError_` | ||
| /// concurrently (Oboe error callbacks fire from an internal thread). | ||
| std::string getLastError() const; | ||
|
Comment on lines
+36
to
+40
|
||
|
|
||
| // oboe::AudioStreamCallback | ||
| oboe::DataCallbackResult onAudioReady( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new comment says “~1.5s @ 192 burst, 48 kHz”, but 128 callbacks * 192 frames / 48kHz is ~0.51s (and the callback frame count may not even be fixed since framesPerDataCallback is unspecified). Please correct or soften the timing estimate to avoid misleading future readers.