From cb28111684fd42014a7d7c05cec8c77cdfd49e03 Mon Sep 17 00:00:00 2001 From: Robert Wu <85952307+robertwu1@users.noreply.github.com> Date: Thu, 27 Feb 2025 13:36:06 -0800 Subject: [PATCH] OboeTester: Add SpatializationBehavior --- .../app/src/main/cpp/NativeAudioContext.cpp | 4 +- .../app/src/main/cpp/NativeAudioContext.h | 4 +- .../app/src/main/cpp/jni-bridge.cpp | 20 ++++++-- .../mobileer/oboetester/OboeAudioStream.java | 12 ++++- .../oboetester/StreamConfiguration.java | 51 +++++++++++++++++++ .../oboetester/StreamConfigurationView.java | 17 +++++++ .../app/src/main/res/layout/stream_config.xml | 22 ++++++++ .../app/src/main/res/values/strings.xml | 7 +++ 8 files changed, 130 insertions(+), 7 deletions(-) diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp index ec1d90172..56c8af0e8 100644 --- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp +++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp @@ -169,7 +169,8 @@ int ActivityContext::open(jint nativeApi, jboolean formatConversionAllowed, jint rateConversionQuality, jboolean isMMap, - jboolean isInput) { + jboolean isInput, + jint spatializationBehavior) { oboe::AudioApi audioApi = oboe::AudioApi::Unspecified; switch (nativeApi) { @@ -210,6 +211,7 @@ int ActivityContext::open(jint nativeApi, ->setChannelConversionAllowed(channelConversionAllowed) ->setFormatConversionAllowed(formatConversionAllowed) ->setSampleRateConversionQuality((oboe::SampleRateConversionQuality) rateConversionQuality) + ->setSpatializationBehavior((oboe::SpatializationBehavior) spatializationBehavior) ; if (channelMask != (jint) oboe::ChannelMask::Unspecified) { // Set channel mask when it is specified. diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h index ffd5b861e..9ec675525 100644 --- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h +++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h @@ -109,6 +109,7 @@ class ActivityContext { * @param rateConversionQuality * @param isMMap * @param isInput + * @param spatializationBehavior * @return stream ID */ int open(jint nativeApi, @@ -128,7 +129,8 @@ class ActivityContext { jboolean formatConversionAllowed, jint rateConversionQuality, jboolean isMMap, - jboolean isInput); + jboolean isInput, + jint spatializationBehavior); oboe::Result release(); diff --git a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp index 74c03eb42..e52407974 100644 --- a/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp +++ b/apps/OboeTester/app/src/main/cpp/jni-bridge.cpp @@ -59,7 +59,8 @@ Java_com_mobileer_oboetester_OboeAudioStream_openNative(JNIEnv *env, jobject, jboolean formatConversionAllowed, jint rateConversionQuality, jboolean isMMap, - jboolean isInput); + jboolean isInput, + jint spatializationBehavior); JNIEXPORT void JNICALL Java_com_mobileer_oboetester_OboeAudioStream_close(JNIEnv *env, jobject, jint); @@ -157,7 +158,8 @@ Java_com_mobileer_oboetester_OboeAudioStream_openNative( jboolean formatConversionAllowed, jint rateConversionQuality, jboolean isMMap, - jboolean isInput) { + jboolean isInput, + jint spatializationBehavior) { LOGD("OboeAudioStream_openNative: sampleRate = %d", sampleRate); return (jint) engine.getCurrentActivity()->open(nativeApi, @@ -177,7 +179,8 @@ Java_com_mobileer_oboetester_OboeAudioStream_openNative( formatConversionAllowed, rateConversionQuality, isMMap, - isInput); + isInput, + spatializationBehavior); } JNIEXPORT jint JNICALL @@ -339,6 +342,17 @@ Java_com_mobileer_oboetester_OboeAudioStream_getInputPreset( return result; } +JNIEXPORT jint JNICALL +Java_com_mobileer_oboetester_OboeAudioStream_getSpatializationBehavior( + JNIEnv *env, jobject, jint streamIndex) { + jint result = (jint) oboe::Result::ErrorNull; + std::shared_ptr oboeStream = engine.getCurrentActivity()->getStream(streamIndex); + if (oboeStream != nullptr) { + result = (jint) oboeStream->getSpatializationBehavior(); + } + return result; +} + JNIEXPORT jint JNICALL Java_com_mobileer_oboetester_OboeAudioStream_getFramesPerBurst( JNIEnv *env, jobject, jint streamIndex) { 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 5c8b21096..6f08767a1 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 @@ -67,7 +67,8 @@ public void open(StreamConfiguration requestedConfiguration, requestedConfiguration.getFormatConversionAllowed(), requestedConfiguration.getRateConversionQuality(), requestedConfiguration.isMMap(), - isInput() + isInput(), + requestedConfiguration.getSpatializationBehavior() ); if (result < 0) { streamIndex = INVALID_STREAM_INDEX; @@ -100,6 +101,7 @@ public void open(StreamConfiguration requestedConfiguration, actualConfiguration.setHardwareChannelCount(getHardwareChannelCount()); actualConfiguration.setHardwareSampleRate(getHardwareSampleRate()); actualConfiguration.setHardwareFormat(getHardwareFormat()); + actualConfiguration.setSpatializationBehavior(getSpatializationBehavior()); } private native int openNative( @@ -120,7 +122,8 @@ private native int openNative( boolean formatConversionAllowed, int rateConversionQuality, boolean isMMap, - boolean isInput); + boolean isInput, + int spatializationBehavior); @Override public void close() { @@ -187,6 +190,11 @@ public int getInputPreset() { } private native int getInputPreset(int streamIndex); + public int getSpatializationBehavior() { + return getSpatializationBehavior(streamIndex); + } + private native int getSpatializationBehavior(int streamIndex); + public int getSampleRate() { return getSampleRate(streamIndex); } diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java index 5e8e88b21..99cc0744c 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfiguration.java @@ -72,6 +72,9 @@ public class StreamConfiguration { public static final int INPUT_PRESET_UNPROCESSED = 9; // must match Oboe public static final int INPUT_PRESET_VOICE_PERFORMANCE = 10; // must match Oboe + public static final int SPATIALIZATION_BEHAVIOR_AUTO = 1; // must match Oboe + public static final int SPATIALIZATION_BEHAVIOR_NEVER = 2; // must match Oboe + public static final int ERROR_BASE = -900; // must match Oboe public static final int ERROR_DISCONNECTED = -899; // must match Oboe public static final int ERROR_ILLEGAL_ARGUMENT = -898; // must match Oboe @@ -298,6 +301,7 @@ public class StreamConfiguration { private int mHardwareChannelCount; private int mHardwareSampleRate; private int mHardwareFormat; + private int mSpatializationBehavior; public StreamConfiguration() { reset(); @@ -351,6 +355,7 @@ public void reset() { mHardwareChannelCount = UNSPECIFIED; mHardwareSampleRate = UNSPECIFIED; mHardwareFormat = UNSPECIFIED; + mSpatializationBehavior = UNSPECIFIED; } public int getFramesPerBurst() { @@ -411,6 +416,11 @@ public void setInputPreset(int inputPreset) { this.mInputPreset = inputPreset; } + public int getSpatializationBehavior() { return mSpatializationBehavior; } + public void setSpatializationBehavior(int spatializationBehavior) { + this.mSpatializationBehavior = spatializationBehavior; + } + public int getUsage() { return mUsage; } public void setUsage(int usage) { this.mUsage = usage; @@ -640,6 +650,8 @@ public String dump() { message.append(String.format(Locale.getDefault(), "%s.hardware.sampleRate = %d\n", prefix, mHardwareSampleRate)); message.append(String.format(Locale.getDefault(), "%s.hardware.format = %s\n", prefix, convertFormatToText(mHardwareFormat).toLowerCase(Locale.getDefault()))); + message.append(String.format(Locale.getDefault(), "%s.spatializationBehavior = %s\n", prefix, + convertSpatializationBehaviorToText(mSpatializationBehavior).toLowerCase(Locale.getDefault()))); return message.toString(); } @@ -697,6 +709,45 @@ public static int convertTextToInputPreset(String text) { return -1; } + // text must match menu values + public static final String NAME_SPATIALIZATION_BEHAVIOR_UNSPECIFIED = "Unspecified"; + public static final String NAME_SPATIALIZATION_BEHAVIOR_AUTO = "Auto"; + public static final String NAME_SPATIALIZATION_BEHAVIOR_NEVER = "Never"; + + public static String convertSpatializationBehaviorToText(int spatializationBehavior) { + switch(spatializationBehavior) { + case UNSPECIFIED: + return NAME_SPATIALIZATION_BEHAVIOR_UNSPECIFIED; + case SPATIALIZATION_BEHAVIOR_AUTO: + return NAME_SPATIALIZATION_BEHAVIOR_AUTO; + case SPATIALIZATION_BEHAVIOR_NEVER: + return NAME_SPATIALIZATION_BEHAVIOR_NEVER; + default: + return "Invalid"; + } + } + + private static boolean matchSpatializationBehavior(String text, int spatializationBehavior) { + return convertSpatializationBehaviorToText(spatializationBehavior).toLowerCase(Locale.getDefault()).equals(text); + } + + /** + * Case insensitive. + * @param text + * @return spatializationBehavior, eg. SPATIALIZATION_BEHAVIOR_NEVER + */ + public static int convertTextToSpatializationBehavior(String text) { + text = text.toLowerCase(Locale.getDefault()); + if (matchSpatializationBehavior(text, UNSPECIFIED)) { + return UNSPECIFIED; + } else if (matchSpatializationBehavior(text, SPATIALIZATION_BEHAVIOR_AUTO)) { + return SPATIALIZATION_BEHAVIOR_AUTO; + } else if (matchSpatializationBehavior(text, SPATIALIZATION_BEHAVIOR_NEVER)) { + return SPATIALIZATION_BEHAVIOR_NEVER; + } + return -1; + } + public int getChannelCount() { return mChannelCount; } diff --git a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java index 3b7edca4c..21eb25ee9 100644 --- a/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java +++ b/apps/OboeTester/app/src/main/java/com/mobileer/oboetester/StreamConfigurationView.java @@ -81,6 +81,10 @@ public class StreamConfigurationView extends LinearLayout { private Spinner mContentTypeSpinner; private TextView mActualContentTypeView; + private TableRow mSpatializationBehaviorTableRow; + private Spinner mSpatializationBehaviorSpinner; + private TextView mActualSpatializationBehaviorView; + private Spinner mFormatSpinner; private Spinner mSampleRateSpinner; private Spinner mRateConversionQualitySpinner; @@ -334,6 +338,10 @@ public void onNothingSelected(AdapterView adapterView) { mActualContentTypeView = (TextView) findViewById(R.id.actualContentType); mContentTypeSpinner = (Spinner) findViewById(R.id.spinnerContentType); + mSpatializationBehaviorTableRow = (TableRow) findViewById(R.id.rowSpatializationBehavior); + mActualSpatializationBehaviorView = (TextView) findViewById(R.id.actualSpatializationBehavior); + mSpatializationBehaviorSpinner = (Spinner) findViewById(R.id.spinnerSpatializationBehavior); + mStreamInfoView = (TextView) findViewById(R.id.streamInfo); mStreamStatusView = (TextView) findViewById(R.id.statusView); @@ -407,6 +415,10 @@ public void applyToModel(StreamConfiguration config) { int contentType = StreamConfiguration.convertTextToContentType(text); config.setContentType(contentType); + text = mSpatializationBehaviorSpinner.getSelectedItem().toString(); + int spatializationBehavior = StreamConfiguration.convertTextToSpatializationBehavior(text); + config.setSpatializationBehavior(spatializationBehavior); + // The corresponding channel count of the selected channel mask may be different from // the selected channel count, the last selected will be respected. if (mIsChannelMaskLastSelected) { @@ -453,6 +465,7 @@ public void setChildrenEnabled(boolean enabled) { mUsageSpinner.setEnabled(enabled); mContentTypeSpinner.setEnabled(enabled); mFormatSpinner.setEnabled(enabled); + mSpatializationBehaviorSpinner.setEnabled(enabled); mSampleRateSpinner.setEnabled(enabled); mRateConversionQualitySpinner.setEnabled(enabled); mDeviceSpinner.setEnabled(enabled); @@ -494,6 +507,10 @@ void updateDisplay(StreamConfiguration actualConfiguration) { mActualContentTypeView.setText(StreamConfiguration.convertContentTypeToText(value)); mActualContentTypeView.requestLayout(); + value = actualConfiguration.getSpatializationBehavior(); + mActualSpatializationBehaviorView.setText(StreamConfiguration.convertSpatializationBehaviorToText(value)); + mActualSpatializationBehaviorView.requestLayout(); + mActualChannelCountView.setText(actualConfiguration.getChannelCount() + ""); mActualSampleRateView.setText(actualConfiguration.getSampleRate() + ""); mActualSessionIdView.setText("S#: " + actualConfiguration.getSessionId()); diff --git a/apps/OboeTester/app/src/main/res/layout/stream_config.xml b/apps/OboeTester/app/src/main/res/layout/stream_config.xml index f06a71e9c..23ad81500 100644 --- a/apps/OboeTester/app/src/main/res/layout/stream_config.xml +++ b/apps/OboeTester/app/src/main/res/layout/stream_config.xml @@ -261,6 +261,28 @@ + + + + + + + + + + Sonification + Spatialization: + + Unspecified + Auto + Never + + Channels: 0