diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h index 740d36329..d58541f9b 100644 --- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h +++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h @@ -341,6 +341,13 @@ class ActivityContext { oboeCallbackProxy->setNotifyWorkloadIncreaseEnabled(enabled); } + void setReportActualDurationDisabled(bool disabled) { + std::shared_ptr stream = getOutputStream(); + if (stream) { + stream->setReportActualDurationDisabled(disabled); + } + } + int32_t setBufferSizeInFrames(int streamIndex, int threshold); virtual void setupMemoryBuffer([[maybe_unused]] std::unique_ptr& buffer, diff --git a/apps/OboeTester/app/src/main/cpp/cpu/AudioWorkloadTest.h b/apps/OboeTester/app/src/main/cpp/cpu/AudioWorkloadTest.h index d375060a4..89f1b125f 100644 --- a/apps/OboeTester/app/src/main/cpp/cpu/AudioWorkloadTest.h +++ b/apps/OboeTester/app/src/main/cpp/cpu/AudioWorkloadTest.h @@ -98,6 +98,9 @@ class AudioWorkloadTest : oboe::AudioStreamDataCallback { return static_cast(result); } + // Apply the current setting for reporting actual duration once the stream exists. + mStream->setReportActualDurationDisabled(mReportActualDurationDisabled); + mFramesPerBurst = mStream->getFramesPerBurst(); mSampleRate = mStream->getSampleRate(); mPreviousXRunCount = 0; @@ -149,7 +152,8 @@ class AudioWorkloadTest : oboe::AudioStreamDataCallback { */ int32_t start(int32_t targetDurationMillis, int32_t numBursts, int32_t numVoices, int32_t alternateNumVoices, int32_t alternatingPeriodMs, bool adpfEnabled, - bool adpfWorkloadIncreaseEnabled, bool hearWorkload) { + bool adpfWorkloadIncreaseEnabled, bool hearWorkload, bool highPerformanceAudio, + bool reportActualDurationDisabled) { std::lock_guard lock(mStreamLock); if (!mStream) { LOGE("Error: Stream not open."); @@ -175,7 +179,13 @@ class AudioWorkloadTest : oboe::AudioStreamDataCallback { mRunning = true; mHearWorkload = hearWorkload; mAdpfWorkloadIncreaseEnabled = adpfWorkloadIncreaseEnabled; + mReportActualDurationDisabled = reportActualDurationDisabled; mStream->setPerformanceHintEnabled(adpfEnabled); + mStream->setReportActualDurationDisabled(mReportActualDurationDisabled); + // Apply performance hint configuration if requested via runner flags. + oboe::PerformanceHintConfig cfg; + cfg.highPerformanceAudio = highPerformanceAudio; + mStream->setPerformanceHintConfig(cfg); mStream->setBufferSizeInFrames(mNumBursts * mFramesPerBurst); mBufferSizeInFrames = mStream->getBufferSizeInFrames(); oboe::Result result = mStream->start(); @@ -422,6 +432,7 @@ class AudioWorkloadTest : oboe::AudioStreamDataCallback { std::atomic mStartTimeMs{0}; std::atomic mHearWorkload{false}; std::atomic mAdpfWorkloadIncreaseEnabled{false}; + std::atomic mReportActualDurationDisabled{false}; // Lock to protect mCallbackStatistics std::mutex mStatisticsLock; diff --git a/apps/OboeTester/app/src/main/cpp/cpu/AudioWorkloadTestRunner.h b/apps/OboeTester/app/src/main/cpp/cpu/AudioWorkloadTestRunner.h index f50f79091..10a32d420 100644 --- a/apps/OboeTester/app/src/main/cpp/cpu/AudioWorkloadTestRunner.h +++ b/apps/OboeTester/app/src/main/cpp/cpu/AudioWorkloadTestRunner.h @@ -74,7 +74,9 @@ class AudioWorkloadTestRunner { int32_t alternatingPeriodMs, bool adpfEnabled, bool adpfWorkloadIncreaseEnabled, - bool hearWorkload) { + bool hearWorkload, + bool highPerformanceAudio, + bool reportActualDurationDisabled) { if (mIsRunning) { LOGE("Error: Test already running."); return -1; @@ -90,15 +92,17 @@ class AudioWorkloadTestRunner { mIsDone = false; mResult = 0; - int32_t result = mAudioWorkloadTest.start( - targetDurationMs, - numBursts, - numVoices, - alternateNumVoices, - alternatingPeriodMs, - adpfEnabled, - adpfWorkloadIncreaseEnabled, - hearWorkload); + int32_t result = mAudioWorkloadTest.start( + targetDurationMs, + numBursts, + numVoices, + alternateNumVoices, + alternatingPeriodMs, + adpfEnabled, + adpfWorkloadIncreaseEnabled, + hearWorkload, + highPerformanceAudio, + reportActualDurationDisabled); if (result != static_cast(oboe::Result::OK)) { mResult = -1; diff --git a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp index bdea4e332..1b68f7b7e 100644 --- a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp +++ b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp @@ -151,6 +151,11 @@ Java_com_mobileer_oboetester_NativeEngine_getCpuCount(JNIEnv *env, jclass type) return sysconf(_SC_NPROCESSORS_CONF); } +JNIEXPORT jboolean JNICALL +Java_com_mobileer_oboetester_NativeEngine_isHighPerformanceAudioSupported(JNIEnv *env, jclass type) { + return oboe::AdpfWrapper::isHighPerformanceAudioSupported(); +} + JNIEXPORT void JNICALL Java_com_mobileer_oboetester_NativeEngine_setCpuAffinityMask(JNIEnv *env, jclass type, @@ -320,6 +325,13 @@ Java_com_mobileer_oboetester_TestAudioActivity_setUseAlternativeAdpf(JNIEnv *env oboe::AdpfWrapper::setUseAlternative(enabled); } +JNIEXPORT void JNICALL +Java_com_mobileer_oboetester_NativeEngine_setReportActualDurationDisabled(JNIEnv *env, + jclass type, + jboolean disabled) { + engine.getCurrentActivity()->setReportActualDurationDisabled(disabled); +} + JNIEXPORT jint JNICALL Java_com_mobileer_oboetester_OboeAudioStream_setBufferSizeInFrames( JNIEnv *env, jobject, jint streamIndex, jint threshold) { @@ -352,6 +364,17 @@ Java_com_mobileer_oboetester_OboeAudioStream_setPerformanceHintEnabled( } } +JNIEXPORT void JNICALL +Java_com_mobileer_oboetester_OboeAudioStream_setPerformanceHintConfig( + JNIEnv *env, jobject, jint streamIndex, jboolean highPerformance) { + std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); + if (oboeStream != nullptr) { + oboe::PerformanceHintConfig cfg; + cfg.highPerformanceAudio = highPerformance; + oboeStream->setPerformanceHintConfig(cfg); + } +} + JNIEXPORT jint JNICALL Java_com_mobileer_oboetester_OboeAudioStream_getBufferCapacityInFrames( JNIEnv *env, jobject, jint streamIndex) { @@ -1206,10 +1229,12 @@ JNIEXPORT jint JNICALL Java_com_mobileer_oboetester_AudioWorkloadTestActivity_start(JNIEnv *env, jobject thiz, jint targetDurationMs, jint numBursts, jint numVoices, jint numAlternateVoices, jint alternatingPeriodMs, jboolean adpfEnabled, jboolean adpfWorkloadIncreaseEnabled, - jboolean hearWorkload) { + jboolean hearWorkload, jboolean highPerformanceAudio, + jboolean reportActualDurationDisabled) { return sAudioWorkload.start(targetDurationMs, numBursts, numVoices, numAlternateVoices, alternatingPeriodMs, adpfEnabled, - adpfWorkloadIncreaseEnabled, hearWorkload); + adpfWorkloadIncreaseEnabled, hearWorkload, highPerformanceAudio, + reportActualDurationDisabled); } JNIEXPORT jint JNICALL @@ -1437,10 +1462,14 @@ Java_com_mobileer_oboetester_AudioWorkloadTestRunnerActivity_start(JNIEnv *env, jint alternatingPeriodMillis, jboolean adpfEnabled, jboolean adpfWorkloadIncreaseEnabled, - jboolean hearWorkload) { - return sAudioWorkloadRunner.start(targetDurationMs, numBursts, numVoices, + jboolean hearWorkload, + jboolean highPerformanceAudio, + jboolean reportActualDurationDisabled) { + int32_t result = sAudioWorkloadRunner.start(targetDurationMs, numBursts, numVoices, alternateNumVoices, alternatingPeriodMillis, adpfEnabled, - adpfWorkloadIncreaseEnabled, hearWorkload); + adpfWorkloadIncreaseEnabled, hearWorkload, highPerformanceAudio, + reportActualDurationDisabled); + return result; } JNIEXPORT jboolean JNICALL diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java index f4915fc05..785133d94 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioStreamBase.java @@ -88,6 +88,12 @@ public void setPerformanceHintEnabled(boolean checked) { } public void setHearWorkload(boolean checked) { } + /** + * Configure performance hint options for this stream. Default implementation is no-op. + * @param highPerformance true to request high performance audio mode when creating the session. + */ + public void setPerformanceHintConfig(boolean highPerformance) { + } public int notifyWorkloadIncrease(boolean cpu, boolean gpu) { return -1; } diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioWorkloadTestActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioWorkloadTestActivity.java index ae144f156..ef8413506 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioWorkloadTestActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioWorkloadTestActivity.java @@ -47,6 +47,8 @@ public class AudioWorkloadTestActivity extends BaseOboeTesterActivity { private CheckBox mEnableAdpfBox; private CheckBox mEnableAdpfWorkloadIncreaseBox; private CheckBox mHearWorkloadBox; + private CheckBox mHighPerformanceAudioBox; + private CheckBox mDisableAdpfDurationBox; private int mCpuCount; private LinearLayout mAffinityLayout; @@ -149,6 +151,9 @@ protected void onCreate(Bundle savedInstanceState) { mEnableAdpfBox = (CheckBox) findViewById(R.id.enable_adpf); mEnableAdpfWorkloadIncreaseBox = (CheckBox) findViewById(R.id.enable_adpf_workload_increase); mHearWorkloadBox = (CheckBox) findViewById(R.id.hear_workload); + mHighPerformanceAudioBox = (CheckBox) findViewById(R.id.high_performance_audio); + + mDisableAdpfDurationBox = (CheckBox) findViewById(R.id.disable_adpf_duration); mOpenButton = (Button) findViewById(R.id.button_open); mStartButton = (Button) findViewById(R.id.button_start); @@ -221,10 +226,13 @@ public void openAudio(View view) { } public void startTest(View view) { + boolean reportActualDurationDisabled = mDisableAdpfDurationBox.isChecked(); + int result = start(mTargetDurationMsSlider.getValue(), mNumBurstsSlider.getValue(), - mNumVoicesSlider.getValue(), mAlternateNumVoicesSlider.getValue(), - mAlternatingPeriodMsSlider.getValue(), mEnableAdpfBox.isChecked(), - mEnableAdpfWorkloadIncreaseBox.isChecked(), mHearWorkloadBox.isChecked()); + mNumVoicesSlider.getValue(), mAlternateNumVoicesSlider.getValue(), + mAlternatingPeriodMsSlider.getValue(), mEnableAdpfBox.isChecked(), + mEnableAdpfWorkloadIncreaseBox.isChecked(), mHearWorkloadBox.isChecked(), + mHighPerformanceAudioBox.isChecked(), reportActualDurationDisabled); if (result != OPERATION_SUCCESS) { showErrorToast("start failed! Error:" + result); return; @@ -318,6 +326,8 @@ public void enableParamsUI(boolean enabled) { mEnableAdpfBox.setEnabled(enabled); mEnableAdpfWorkloadIncreaseBox.setEnabled(enabled); mHearWorkloadBox.setEnabled(enabled); + mHighPerformanceAudioBox.setEnabled(enabled); + mDisableAdpfDurationBox.setEnabled(enabled); } public void updateStreamInfoView() { @@ -331,7 +341,8 @@ public void updateStreamInfoView() { private native int getBufferSizeInFrames(); private native int start(int targetDurationMs, int numBursts, int numVoices, int numAlternateVoices, int alternatingPeriodMs, boolean adpfEnabled, - boolean adpfWorkloadIncreaseEnabled, boolean hearWorkload); + boolean adpfWorkloadIncreaseEnabled, boolean hearWorkload, + boolean highPerformanceAudio, boolean reportActualDurationDisabled); private native int getCpuCount(); private native int setCpuAffinityForCallback(int mask); private native int getXRunCount(); diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioWorkloadTestRunnerActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioWorkloadTestRunnerActivity.java index 79924b4dd..ba13f1e00 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioWorkloadTestRunnerActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/AudioWorkloadTestRunnerActivity.java @@ -38,6 +38,8 @@ public class AudioWorkloadTestRunnerActivity extends BaseOboeTesterActivity { private CheckBox mEnableAdpfBox; private CheckBox mEnableAdpfWorkloadIncreaseBox; private CheckBox mHearWorkloadBox; + private CheckBox mHighPerformanceAudioBox; + private CheckBox mDisableAdpfDurationBox; private Button mStartButton; private Button mStopButton; @@ -79,6 +81,8 @@ protected void onCreate(Bundle savedInstanceState) { mEnableAdpfBox = findViewById(R.id.enable_adpf); mEnableAdpfWorkloadIncreaseBox = findViewById(R.id.enable_adpf_workload_increase); mHearWorkloadBox = findViewById(R.id.hear_workload); + mHighPerformanceAudioBox = findViewById(R.id.high_performance_audio); + mDisableAdpfDurationBox = findViewById(R.id.disable_adpf_duration); mStartButton = findViewById(R.id.button_start_test); mStopButton = findViewById(R.id.button_stop_test); @@ -107,9 +111,12 @@ public void startTest(View view) { boolean adpfEnabled = mEnableAdpfBox.isChecked(); boolean adpfWorkloadIncreaseEnabled = mEnableAdpfWorkloadIncreaseBox.isChecked(); boolean hearWorkload = mHearWorkloadBox.isChecked(); + boolean highPerformanceAudio = mHighPerformanceAudioBox.isChecked(); + boolean reportActualDurationDisabled = mDisableAdpfDurationBox.isChecked(); int result = start(targetDurationMs, numBursts, numVoices, alternateNumVoices, - alternatingPeriodMs, adpfEnabled, adpfWorkloadIncreaseEnabled, hearWorkload); + alternatingPeriodMs, adpfEnabled, adpfWorkloadIncreaseEnabled, hearWorkload, + highPerformanceAudio, reportActualDurationDisabled); if (result != OPERATION_SUCCESS) { showErrorToast("start failed! Error:" + result); return; @@ -144,6 +151,8 @@ public void enableParamsUI(boolean enabled) { mEnableAdpfBox.setEnabled(enabled); mEnableAdpfWorkloadIncreaseBox.setEnabled(enabled); mHearWorkloadBox.setEnabled(enabled); + mHighPerformanceAudioBox.setEnabled(enabled); + mDisableAdpfDurationBox.setEnabled(enabled); } private void updateResultTextView() { @@ -160,7 +169,9 @@ private void updateResultTextView() { public native int start(int targetDurationMs, int numBursts, int numVoices, int alternateNumVoices, int alternatingPeriodMs, boolean adpfEnabled, - boolean adpfWorkloadIncreaseEnabled, boolean hearWorkload); + boolean adpfWorkloadIncreaseEnabled, boolean hearWorkload, + boolean highPerformanceAudio, + boolean reportActualDurationDisabled); public native boolean stopIfDone(); public native String getStatus(); public native int stop(); diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DynamicWorkloadActivity.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DynamicWorkloadActivity.java index 67d2375c0..eb9ea45d9 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DynamicWorkloadActivity.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/DynamicWorkloadActivity.java @@ -65,6 +65,10 @@ public class DynamicWorkloadActivity extends TestOutputActivityBase { public static final boolean VALUE_DEFAULT_SCROLL_GRAPHICS = false; public static final String KEY_USE_WORKLOAD_INCREASE_API = "use_workload_increase_api"; public static final boolean VALUE_DEFAULT_USE_WORKLOAD_INCREASE_API = false; + public static final String KEY_USE_HIGH_PERFORMANCE_AUDIO = "use_high_performance_audio"; + public static final boolean VALUE_DEFAULT_USE_HIGH_PERFORMANCE_AUDIO = false; + public static final String KEY_DISABLE_ADPF_DURATION = "disable_adpf_duration"; + public static final boolean VALUE_DEFAULT_DISABLE_ADPF_DURATION = false; private Button mStopButton; private Button mStartButton; @@ -79,6 +83,8 @@ public class DynamicWorkloadActivity extends TestOutputActivityBase { private CheckBox mUseAltAdpfBox; private CheckBox mPerfHintBox; private CheckBox mWorkloadReportBox; + private CheckBox mHighPerformanceAudioBox; + private CheckBox mDisableAdpfDurationBox; private boolean mDrawChartAlways = true; private CheckBox mDrawAlwaysBox; private CheckBox mSustainedPerformanceModeBox; @@ -88,6 +94,8 @@ public class DynamicWorkloadActivity extends TestOutputActivityBase { private boolean mShouldUseWorkloadReporting; private boolean mEnableWorkloadIncreaseApi; private int mLastNotifyWorkloadResult; + private boolean mShouldUseHighPerformanceAudio; + private boolean mDisableAdpfDuration; private static final int WORKLOAD_LOW = 1; private int mWorkloadHigh; // this will get set later @@ -309,6 +317,15 @@ public void onClick(View view) { mPerfHintBox = (CheckBox) findViewById(R.id.enable_perf_hint); mWorkloadReportBox = (CheckBox) findViewById(R.id.enable_workload_report); + mHighPerformanceAudioBox = (CheckBox) findViewById(R.id.high_performance_audio); + + // If the platform does not support the high-performance-audio APERF feature, + // hide or disable the UI control so users don't attempt to enable it. + boolean hpSupported = NativeEngine.isHighPerformanceAudioSupported(); + if (!hpSupported) { + mHighPerformanceAudioBox.setEnabled(false); + mHighPerformanceAudioBox.setVisibility(View.GONE); + } // TODO remove when finished with ADPF experiments. mUseAltAdpfBox = (CheckBox) findViewById(R.id.use_alternative_adpf); @@ -319,6 +336,13 @@ public void onClick(View view) { }); mUseAltAdpfBox.setVisibility(View.GONE); + mDisableAdpfDurationBox = (CheckBox) findViewById(R.id.disable_adpf_duration); + mDisableAdpfDurationBox.setOnClickListener(buttonView -> { + CheckBox checkBox = (CheckBox) buttonView; + NativeEngine.setReportActualDurationDisabled(checkBox.isChecked()); + }); + NativeEngine.setReportActualDurationDisabled(mDisableAdpfDurationBox.isChecked()); + mPerfHintBox.setOnClickListener(buttonView -> { CheckBox checkBox = (CheckBox) buttonView; mShouldUseADPF = checkBox.isChecked(); @@ -326,6 +350,7 @@ public void onClick(View view) { mUseAltAdpfBox.setEnabled(!mShouldUseADPF); mWorkloadReportBox.setEnabled(mShouldUseADPF); mWorkloadIncreaseApiBox.setEnabled(mShouldUseADPF); + mHighPerformanceAudioBox.setEnabled(!mShouldUseADPF); }); mWorkloadReportBox.setOnClickListener(buttonView -> { @@ -343,6 +368,11 @@ public void onClick(View view) { }); mWorkloadIncreaseApiBox.setEnabled(mEnableWorkloadIncreaseApi); + mHighPerformanceAudioBox.setOnClickListener(buttonView -> { + CheckBox checkBox = (CheckBox) buttonView; + mAudioOutTester.getCurrentAudioStream().setPerformanceHintConfig(checkBox.isChecked()); + }); + CheckBox hearWorkloadBox = (CheckBox) findViewById(R.id.hear_workload); hearWorkloadBox.setOnClickListener(buttonView -> { CheckBox checkBox = (CheckBox) buttonView; @@ -395,6 +425,13 @@ private void setWorkloadReportingEnabled(boolean enabled) { NativeEngine.setWorkloadReportingEnabled(enabled); } + private void setHighPerformanceAudio(boolean enabled) { + mShouldUseHighPerformanceAudio = enabled; + if (mAudioOutTester != null && mAudioOutTester.getCurrentAudioStream() != null) { + mAudioOutTester.getCurrentAudioStream().setPerformanceHintConfig(enabled); + } + } + private void setNotifyWorkloadIncreaseEnabled(boolean enabled) { NativeEngine.setNotifyWorkloadIncreaseEnabled(enabled); } @@ -434,6 +471,7 @@ private void startTest() { } try { super.startAudio(); + setHighPerformanceAudio(mShouldUseHighPerformanceAudio); setPerformanceHintEnabled(mShouldUseADPF); updateButtons(true); postResult("Running test"); @@ -477,10 +515,15 @@ public void startTestUsingBundle() { VALUE_DEFAULT_SCROLL_GRAPHICS); mEnableWorkloadIncreaseApi = mBundleFromIntent.getBoolean(KEY_USE_WORKLOAD_INCREASE_API, VALUE_DEFAULT_USE_WORKLOAD_INCREASE_API); - + mShouldUseHighPerformanceAudio = mBundleFromIntent.getBoolean(KEY_USE_HIGH_PERFORMANCE_AUDIO, + VALUE_DEFAULT_USE_HIGH_PERFORMANCE_AUDIO); + mDisableAdpfDuration = mBundleFromIntent.getBoolean(KEY_DISABLE_ADPF_DURATION, + VALUE_DEFAULT_DISABLE_ADPF_DURATION); startTest(); runOnUiThread(() -> { + mHighPerformanceAudioBox.setChecked(mShouldUseHighPerformanceAudio); + setHighPerformanceAudio(mShouldUseHighPerformanceAudio); mPerfHintBox.setChecked(mShouldUseADPF); setPerformanceHintEnabled(mShouldUseADPF); mWorkloadReportBox.setChecked(mShouldUseWorkloadReporting); @@ -488,6 +531,8 @@ public void startTestUsingBundle() { mWorkloadIncreaseApiBox.setChecked(mEnableWorkloadIncreaseApi); setNotifyWorkloadIncreaseEnabled(mEnableWorkloadIncreaseApi); mDrawAlwaysBox.setChecked(mDrawChartAlways); + mDisableAdpfDurationBox.setChecked(mDisableAdpfDuration); + NativeEngine.setReportActualDurationDisabled(mDisableAdpfDuration); }); diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java index 2a5f36b7f..fa82fcfc6 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/NativeEngine.java @@ -6,6 +6,8 @@ public class NativeEngine { static native boolean isMMapExclusiveSupported(); + static native boolean isHighPerformanceAudioSupported(); + static native void setWorkaroundsEnabled(boolean enabled); static native boolean areWorkaroundsEnabled(); @@ -17,4 +19,6 @@ public class NativeEngine { static native void setWorkloadReportingEnabled(boolean enabled); static native void setNotifyWorkloadIncreaseEnabled(boolean enabled); + + static native void setReportActualDurationDisabled(boolean disabled); } diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java index a151af09d..bf6008aa2 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/OboeAudioStream.java @@ -171,6 +171,12 @@ public void setPerformanceHintEnabled(boolean checked) { } private native void setPerformanceHintEnabled(int streamIndex, boolean checked); + @Override + public void setPerformanceHintConfig(boolean highPerformance) { + setPerformanceHintConfig(mStreamIndex, highPerformance); + } + private native void setPerformanceHintConfig(int streamIndex, boolean highPerformance); + @Override public void setHearWorkload(boolean checked) { setHearWorkload(mStreamIndex, checked); diff --git a/apps/OboeTester/app/src/main/res/layout/activity_audio_workload_test.xml b/apps/OboeTester/app/src/main/res/layout/activity_audio_workload_test.xml index b041938ed..61c0bc69d 100644 --- a/apps/OboeTester/app/src/main/res/layout/activity_audio_workload_test.xml +++ b/apps/OboeTester/app/src/main/res/layout/activity_audio_workload_test.xml @@ -148,8 +148,34 @@ android:layout_height="wrap_content" android:layout_marginRight="8sp" android:text="Hear Workload" /> + + + + + + + + + + + + + + + + + + + + mWeakThis; // weak pointer to this object + // Performance hint configuration for this stream. + PerformanceHintConfig mPerformanceHintConfig; /** * Number of frames which have been written into the stream diff --git a/src/aaudio/AudioStreamAAudio.cpp b/src/aaudio/AudioStreamAAudio.cpp index d8fa4e43b..06acd9925 100644 --- a/src/aaudio/AudioStreamAAudio.cpp +++ b/src/aaudio/AudioStreamAAudio.cpp @@ -283,7 +283,8 @@ void AudioStreamAAudio::beginPerformanceHintInCallback() { if (!mAdpfOpenAttempted) { int64_t targetDurationNanos = (mFramesPerBurst * 1e9) / getSampleRate(); // This has to be called from the callback thread so we get the right TID. - int adpfResult = mAdpfWrapper.open(gettid(), targetDurationNanos); + int adpfResult = mAdpfWrapper.open(gettid(), targetDurationNanos, + mPerformanceHintConfig.highPerformanceAudio); if (adpfResult < 0) { LOGW("WARNING ADPF not supported, %d\n", adpfResult); } else { diff --git a/src/aaudio/AudioStreamAAudio.h b/src/aaudio/AudioStreamAAudio.h index d188952b1..60ba17f23 100644 --- a/src/aaudio/AudioStreamAAudio.h +++ b/src/aaudio/AudioStreamAAudio.h @@ -100,6 +100,10 @@ class AudioStreamAAudio : public AudioStream { mAdpfOpenAttempted = false; } + void setReportActualDurationDisabled(bool disabled) override { + mAdpfWrapper.setReportActualDurationDisabled(disabled); + } + oboe::Result reportWorkload(int32_t appWorkload) override { if (!isPerformanceHintEnabled()) { return oboe::Result::ErrorInvalidState; diff --git a/src/common/AdpfWrapper.cpp b/src/common/AdpfWrapper.cpp index 4fcae60c9..533e22252 100644 --- a/src/common/AdpfWrapper.cpp +++ b/src/common/AdpfWrapper.cpp @@ -35,6 +35,13 @@ typedef void (*APH_closeSession)(APerformanceHintSession* session); typedef int (*APH_notifyWorkloadIncrease)(APerformanceHintSession*, bool, bool, const char*); typedef int (*APH_notifyWorkloadSpike)(APerformanceHintSession*, bool, bool, const char*); typedef int (*APH_notifyWorkloadReset)(APerformanceHintSession*, bool, bool, const char*); +typedef int (*APH_createSessionUsingConfig)(APerformanceHintManager*, void* /*ASessionCreationConfig*/, APerformanceHintSession**); +typedef void* (*APH_sessionConfig_create)(); +typedef void (*APH_sessionConfig_release)(void*); +typedef void (*APH_sessionConfig_setTids)(void*, const pid_t*, size_t); +typedef void (*APH_sessionConfig_setTargetWorkDurationNanos)(void*, int64_t); +typedef void (*APH_sessionConfig_setAudioPerformance)(void*, bool); +typedef bool (*APH_isFeatureSupported)(void* /*APerformanceHintFeature*/); static bool gAPerformanceHintBindingInitialized = false; static APH_getManager gAPH_getManagerFn = nullptr; @@ -44,11 +51,26 @@ static APH_closeSession gAPH_closeSessionFn = nullptr; static APH_notifyWorkloadIncrease gAPH_notifyWorkloadIncreaseFn = nullptr; static APH_notifyWorkloadSpike gAPH_notifyWorkloadSpikeFn = nullptr; static APH_notifyWorkloadReset gAPH_notifyWorkloadResetFn = nullptr; +static APH_createSessionUsingConfig gAPH_createSessionUsingConfigFn = nullptr; +static APH_sessionConfig_create gAPH_sessionConfigCreateFn = nullptr; +static APH_sessionConfig_release gAPH_sessionConfigReleaseFn = nullptr; +static APH_sessionConfig_setTids gAPH_sessionConfigSetTidsFn = nullptr; +static APH_sessionConfig_setTargetWorkDurationNanos gAPH_sessionConfigSetTargetWorkDurationNanosFn = nullptr; +static APH_sessionConfig_setAudioPerformance gAPH_sessionConfigSetAudioPerformanceFn = nullptr; +static APH_isFeatureSupported gAPH_isFeatureSupportedFn = nullptr; #ifndef __ANDROID_API_B__ #define __ANDROID_API_B__ 36 #endif +#ifndef APERF_HINT_SESSIONS +#define APERF_HINT_SESSIONS 0 +#endif + +#ifndef APERF_HINT_AUDIO_PERFORMANCE +#define APERF_HINT_AUDIO_PERFORMANCE 6 +#endif + static int loadAphFunctions() { if (gAPerformanceHintBindingInitialized) return true; @@ -95,6 +117,20 @@ static int loadAphFunctions() { if (gAPH_notifyWorkloadResetFn == nullptr) { return -1007; } + + // Optional config-based session creation (API 36+). These may be missing on older + // platforms or pre-release builds; load them if available. + gAPH_createSessionUsingConfigFn = (APH_createSessionUsingConfig)dlsym( + handle_, "APerformanceHint_createSessionUsingConfig"); + gAPH_sessionConfigCreateFn = (APH_sessionConfig_create)dlsym(handle_, "ASessionCreationConfig_create"); + gAPH_sessionConfigReleaseFn = (APH_sessionConfig_release)dlsym(handle_, "ASessionCreationConfig_release"); + gAPH_sessionConfigSetTidsFn = (APH_sessionConfig_setTids)dlsym(handle_, "ASessionCreationConfig_setTids"); + gAPH_sessionConfigSetTargetWorkDurationNanosFn = (APH_sessionConfig_setTargetWorkDurationNanos)dlsym( + handle_, "ASessionCreationConfig_setTargetWorkDurationNanos"); + gAPH_sessionConfigSetAudioPerformanceFn = (APH_sessionConfig_setAudioPerformance)dlsym( + handle_, "ASessionCreationConfig_setAudioPerformance"); + gAPH_isFeatureSupportedFn = (APH_isFeatureSupported)dlsym( + handle_, "APerformanceHint_isFeatureSupported"); } gAPerformanceHintBindingInitialized = true; @@ -104,8 +140,24 @@ static int loadAphFunctions() { bool AdpfWrapper::sUseAlternativeHack = false; // TODO remove hack +void AdpfWrapper::setReportActualDurationDisabled(bool disabled) { + mIsReportActualDurationDisabled = disabled; +} + +bool AdpfWrapper::isHighPerformanceAudioSupported() { + // Ensure the performance hint functions are loaded. + int result = loadAphFunctions(); + if (result < 0) return false; + if (gAPH_isFeatureSupportedFn == nullptr) return false; + // The binding expects a feature identifier; we use the integer constant + // APERF_HINT_AUDIO_PERFORMANCE cast into the expected parameter type. + return gAPH_isFeatureSupportedFn( + reinterpret_cast(static_cast(APERF_HINT_AUDIO_PERFORMANCE))); +} + int AdpfWrapper::open(pid_t threadId, - int64_t targetDurationNanos) { + int64_t targetDurationNanos, + bool highPerformanceAudio) { std::lock_guard lock(mLock); int result = loadAphFunctions(); if (result < 0) return result; @@ -120,6 +172,41 @@ int AdpfWrapper::open(pid_t threadId, // algorithm that is not based on PID. targetDurationNanos = (targetDurationNanos & ~0xFF) | 0xA5; } + // If caller requested highPerformanceAudio and we have the newer config-based + // session creation API, try to create a session with a creation config. + if (highPerformanceAudio && gAPH_isFeatureSupportedFn != nullptr + && gAPH_isFeatureSupportedFn( + reinterpret_cast(static_cast(APERF_HINT_SESSIONS))) + && gAPH_isFeatureSupportedFn( + reinterpret_cast(static_cast(APERF_HINT_AUDIO_PERFORMANCE))) + && gAPH_createSessionUsingConfigFn != nullptr + && gAPH_sessionConfigCreateFn != nullptr + && gAPH_sessionConfigReleaseFn != nullptr + && gAPH_sessionConfigSetTidsFn != nullptr + && gAPH_sessionConfigSetTargetWorkDurationNanosFn != nullptr + && gAPH_sessionConfigSetAudioPerformanceFn != nullptr) { + + void* config = gAPH_sessionConfigCreateFn(); + if (config != nullptr) { + // set tids + gAPH_sessionConfigSetTidsFn(config, &thread32, 1); + // set target duration + gAPH_sessionConfigSetTargetWorkDurationNanosFn(config, targetDurationNanos); + // set high performance audio hint + gAPH_sessionConfigSetAudioPerformanceFn(config, true); + + APerformanceHintSession *sessionOut = nullptr; + int createResult = gAPH_createSessionUsingConfigFn(manager, config, &sessionOut); + // release config now + gAPH_sessionConfigReleaseFn(config); + if (createResult == 0 && sessionOut != nullptr) { + mHintSession = sessionOut; + return 0; + } + // otherwise fall through to legacy createSession + } + } + mHintSession = gAPH_createSessionFn(manager, &thread32, 1 /* size */, targetDurationNanos); if (mHintSession == nullptr) { return -1; @@ -128,6 +215,8 @@ int AdpfWrapper::open(pid_t threadId, } void AdpfWrapper::reportActualDuration(int64_t actualDurationNanos) { + // Skip reporting when disabled; report only when enabled. + if (mIsReportActualDurationDisabled) return; //LOGD("ADPF Oboe %s(dur=%lld)", __func__, (long long)actualDurationNanos); std::lock_guard lock(mLock); if (mHintSession != nullptr) { diff --git a/src/common/AdpfWrapper.h b/src/common/AdpfWrapper.h index b12e0847c..9abaf3bdc 100644 --- a/src/common/AdpfWrapper.h +++ b/src/common/AdpfWrapper.h @@ -43,7 +43,8 @@ namespace oboe { * @return zero or negative error */ int open(pid_t threadId, - int64_t targetDurationNanos); + int64_t targetDurationNanos, + bool highPerformanceAudio = false); bool isOpen() const { return (mHintSession != nullptr); @@ -71,6 +72,20 @@ namespace oboe { sUseAlternativeHack = enabled; } + /** + * Control whether the actual duration reporting to ADPF is disabled. + * @param disabled set true to disable reporting; false to enable. + */ + void setReportActualDurationDisabled(bool disabled); + + /** + * Return true if the platform reports support for the high-performance-audio + * feature (APerfHintFeature::APERF_HINT_HIGH_PERFORMANCE_AUDIO). + * This is a static helper that will attempt to bind to the native API if + * necessary. + */ + static bool isHighPerformanceAudioSupported(); + /** * Report the measured duration of a callback. * This is normally called by onEndCallback(). @@ -168,6 +183,7 @@ namespace oboe { APerformanceHintSession *mHintSession = nullptr; int64_t mBeginCallbackNanos = 0; static bool sUseAlternativeHack; + bool mIsReportActualDurationDisabled = false; int32_t mPreviousWorkload = 0; double mNanosPerWorkloadUnit = 0.0; }; diff --git a/src/common/AudioStream.cpp b/src/common/AudioStream.cpp index b3f7e26e8..6dc4f89d0 100644 --- a/src/common/AudioStream.cpp +++ b/src/common/AudioStream.cpp @@ -25,6 +25,7 @@ #include "oboe/Utilities.h" #include "OboeDebug.h" +#include "Trace.h" namespace oboe { @@ -70,6 +71,10 @@ DataCallbackResult AudioStream::fireDataCallback(void *audioData, int32_t numFra beginPerformanceHintInCallback(); + if (Trace::getInstance().isEnabled()) { + Trace::getInstance().beginSection("OboeCallback"); + } + // Call the app to do the work. DataCallbackResult result; if (mDataCallback) { @@ -77,6 +82,11 @@ DataCallbackResult AudioStream::fireDataCallback(void *audioData, int32_t numFra } else { result = onDefaultCallback(audioData, numFrames); } + + if (Trace::getInstance().isEnabled()) { + Trace::getInstance().endSection(); + } + // On Oreo, we might get called after returning stop. // So block that here. setDataCallbackEnabled(result == DataCallbackResult::Continue); @@ -94,6 +104,10 @@ int32_t AudioStream::firePartialDataCallback(void *audioData, int numFrames) { beginPerformanceHintInCallback(); + if (Trace::getInstance().isEnabled()) { + Trace::getInstance().beginSection("PartialOboeCallback"); + } + // Call the app to do the work. int32_t result; if (mPartialDataCallback) { @@ -103,6 +117,10 @@ int32_t AudioStream::firePartialDataCallback(void *audioData, int numFrames) { result = -1; // This should not happen, return negative value to stop the stream. } + if (Trace::getInstance().isEnabled()) { + Trace::getInstance().endSection(); + } + endPerformanceHintInCallback(numFrames); return result;