Skip to content
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

Add hardware stream functions for API 34 #1744

Merged
merged 3 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions apps/OboeTester/app/src/main/cpp/jni-bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,38 @@ Java_com_mobileer_oboetester_OboeAudioStream_getFormat(JNIEnv *env, jobject inst
return result;
}

JNIEXPORT jint JNICALL
Java_com_mobileer_oboetester_OboeAudioStream_getHardwareChannelCount(
JNIEnv *env, jobject, jint streamIndex) {
jint result = (jint) oboe::Result::ErrorNull;
std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
if (oboeStream != nullptr) {
result = oboeStream->getHardwareChannelCount();
}
return result;
}

JNIEXPORT jint JNICALL
Java_com_mobileer_oboetester_OboeAudioStream_getHardwareFormat(JNIEnv *env, jobject instance, jint streamIndex) {
jint result = (jint) oboe::Result::ErrorNull;
std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
if (oboeStream != nullptr) {
result = (jint) oboeStream->getHardwareFormat();
}
return result;
}

JNIEXPORT jint JNICALL
Java_com_mobileer_oboetester_OboeAudioStream_getHardwareSampleRate(
JNIEnv *env, jobject, jint streamIndex) {
jint result = (jint) oboe::Result::ErrorNull;
std::shared_ptr<oboe::AudioStream> oboeStream = engine.getCurrentActivity()->getStream(streamIndex);
if (oboeStream != nullptr) {
result = oboeStream->getHardwareSampleRate();
}
return result;
}

JNIEXPORT jint JNICALL
Java_com_mobileer_oboetester_OboeAudioStream_getUsage(JNIEnv *env, jobject instance, jint streamIndex) {
jint result = (jint) oboe::Result::ErrorNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ public void open(StreamConfiguration requestedConfiguration,
actualConfiguration.setDirection(isInput()
? StreamConfiguration.DIRECTION_INPUT
: StreamConfiguration.DIRECTION_OUTPUT);
actualConfiguration.setHardwareChannelCount(getHardwareChannelCount());
actualConfiguration.setHardwareSampleRate(getHardwareSampleRate());
actualConfiguration.setHardwareFormat(getHardwareFormat());
}

private native int openNative(
Expand Down Expand Up @@ -207,6 +210,21 @@ public int getChannelMask() {
}
private native int getChannelMask(int streamIndex);

public int getHardwareChannelCount() {
return getHardwareChannelCount(streamIndex);
}
private native int getHardwareChannelCount(int streamIndex);

public int getHardwareSampleRate() {
return getHardwareSampleRate(streamIndex);
}
private native int getHardwareSampleRate(int streamIndex);

public int getHardwareFormat() {
return getHardwareFormat(streamIndex);
}
private native int getHardwareFormat(int streamIndex);

public int getDeviceId() {
return getDeviceId(streamIndex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,9 @@ public class StreamConfiguration {
private int mFramesPerBurst;
private boolean mMMap;
private int mChannelMask;
private int mHardwareChannelCount;
private int mHardwareSampleRate;
private int mHardwareFormat;

public StreamConfiguration() {
reset();
Expand Down Expand Up @@ -328,6 +331,9 @@ public void reset() {
mChannelConversionAllowed = false;
mRateConversionQuality = RATE_CONVERSION_QUALITY_NONE;
mMMap = NativeEngine.isMMapSupported();
mHardwareChannelCount = UNSPECIFIED;
mHardwareSampleRate = UNSPECIFIED;
mHardwareFormat = UNSPECIFIED;
}

public int getFramesPerBurst() {
Expand Down Expand Up @@ -592,6 +598,10 @@ public String dump() {
message.append(String.format(Locale.getDefault(), "%s.device = %d\n", prefix, mDeviceId));
message.append(String.format(Locale.getDefault(), "%s.mmap = %s\n", prefix, isMMap() ? "yes" : "no"));
message.append(String.format(Locale.getDefault(), "%s.rate.conversion.quality = %d\n", prefix, mRateConversionQuality));
message.append(String.format(Locale.getDefault(), "%s.hardware.channels = %d\n", prefix, mHardwareChannelCount));
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())));
return message.toString();
}

Expand Down Expand Up @@ -727,4 +737,27 @@ public static List<String> getAllChannelMasks() {
return mChannelMaskStrings;
}

public int getHardwareChannelCount() {
return mHardwareChannelCount;
}

public void setHardwareChannelCount(int hardwareChannelCount) {
this.mHardwareChannelCount = hardwareChannelCount;
}

public int getHardwareSampleRate() {
return mHardwareSampleRate;
}

public void setHardwareSampleRate(int hardwareSampleRate) {
this.mHardwareSampleRate = hardwareSampleRate;
}

public int getHardwareFormat() {
return mHardwareFormat;
}

public void setHardwareFormat(int hardwareFormat) {
this.mHardwareFormat = hardwareFormat;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -469,12 +469,25 @@ void updateDisplay(StreamConfiguration actualConfiguration) {
mActualChannelMaskView.setText(StreamConfiguration.convertChannelMaskToText(value));

boolean isMMap = actualConfiguration.isMMap();
mStreamInfoView.setText("burst = " + actualConfiguration.getFramesPerBurst()
+ ", capacity = " + actualConfiguration.getBufferCapacityInFrames()
+ ", devID = " + actualConfiguration.getDeviceId()
+ ", " + (actualConfiguration.isMMap() ? "MMAP" : "Legacy")
+ (isMMap ? ", " + StreamConfiguration.convertSharingModeToText(sharingMode) : "")
);

String msg = "";
msg += "burst = " + actualConfiguration.getFramesPerBurst();
msg += ", capacity = " + actualConfiguration.getBufferCapacityInFrames();
msg += ", devID = " + actualConfiguration.getDeviceId();
msg += ", " + (actualConfiguration.isMMap() ? "MMAP" : "Legacy");
msg += (isMMap ? ", " + StreamConfiguration.convertSharingModeToText(sharingMode) : "");

int hardwareChannelCount = actualConfiguration.getHardwareChannelCount();
int hardwareSampleRate = actualConfiguration.getHardwareSampleRate();
int hardwareFormat = actualConfiguration.getHardwareFormat();
msg += "\nHW: #ch=" + (hardwareChannelCount ==
StreamConfiguration.UNSPECIFIED ? "?" : hardwareChannelCount);
msg += ", SR=" + (hardwareSampleRate ==
StreamConfiguration.UNSPECIFIED ? "?" : hardwareSampleRate);
msg += ", format=" + (hardwareFormat == StreamConfiguration.UNSPECIFIED ?
"?" : StreamConfiguration.convertFormatToText(hardwareFormat));

mStreamInfoView.setText(msg);

mHideableView.requestLayout();
}
Expand Down
1 change: 1 addition & 0 deletions apps/OboeTester/app/src/main/res/layout/stream_config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@
android:id="@+id/streamInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:lines="2"
android:text="info:" />

<TextView
Expand Down
22 changes: 22 additions & 0 deletions include/oboe/AudioStreamBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,21 @@ class AudioStreamBase {
return mChannelMask;
}

/**
* @return number of channels for the hardware, for example 2 for stereo, or kUnspecified.
*/
int32_t getHardwareChannelCount() const { return mHardwareChannelCount; }

/**
* @return hardware sample rate for the stream or kUnspecified
*/
int32_t getHardwareSampleRate() const { return mHardwareSampleRate; }

/**
* @return the audio sample format of the hardware (e.g. Float or I16)
*/
AudioFormat getHardwareFormat() const { return mHardwareFormat; }

protected:
/** The callback which will be fired when new data is ready to be read/written. **/
AudioStreamDataCallback *mDataCallback = nullptr;
Expand Down Expand Up @@ -234,6 +249,13 @@ class AudioStreamBase {
/** Control the attribution tag of the context creating the stream. Only active on Android 31+ */
std::string mAttributionTag;

/** Hardware channel count. Only specified on Android 34+ AAudio streams */
int32_t mHardwareChannelCount = kUnspecified;
/** Hardware sample rate. Only specified on Android 34+ AAudio streams */
int32_t mHardwareSampleRate = kUnspecified;
/** Hardware format. Only specified on Android 34+ AAudio streams */
AudioFormat mHardwareFormat = AudioFormat::Unspecified;

// Control whether Oboe can convert channel counts to achieve optimal results.
bool mChannelConversionAllowed = false;
// Control whether Oboe can convert data formats to achieve optimal results.
Expand Down
2 changes: 2 additions & 0 deletions include/oboe/Definitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ namespace oboe {

/**
* Unspecified format. Format will be decided by Oboe.
* When calling getHardwareFormat(), this will be returned if
* the API is not supported.
*/
Unspecified = 0, // AAUDIO_FORMAT_UNSPECIFIED,

Expand Down
10 changes: 10 additions & 0 deletions include/oboe/Utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ int getPropertyInteger(const char * name, int defaultValue);
*/
int getSdkVersion();

/**
* Returns whether a device is on a pre-release SDK that is at least the specified codename
* version.
*
* @param codename the code name to verify.
* @return boolean of whether the device is on a pre-release SDK and is at least the specified
* codename
*/
bool isAtLeastPreReleaseCodename(const std::string& codename);

int getChannelCountFromChannelMask(ChannelMask channelMask);

} // namespace oboe
Expand Down
8 changes: 8 additions & 0 deletions src/aaudio/AAudioLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ int AAudioLoader::open() {
if (getSdkVersion() >= __ANDROID_API_S_V2__) {
stream_getChannelMask = load_U_PS("AAudioStream_getChannelMask");
}

// TODO: Remove pre-release check after Android U release
if (getSdkVersion() >= __ANDROID_API_U__ || isAtLeastPreReleaseCodename("UpsideDownCake")) {
stream_getHardwareChannelCount = load_I_PS("AAudioStream_getHardwareChannelCount");
stream_getHardwareSampleRate = load_I_PS("AAudioStream_getHardwareSampleRate");
stream_getHardwareFormat = load_F_PS("AAudioStream_getHardwareFormat");
}

return 0;
}

Expand Down
8 changes: 8 additions & 0 deletions src/aaudio/AAudioLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ typedef uint32_t aaudio_channel_mask_t;
#define __ANDROID_API_S_V2__ 32
#endif

#ifndef __ANDROID_API_U__
#define __ANDROID_API_U__ 34
#endif

namespace oboe {

/**
Expand Down Expand Up @@ -230,6 +234,10 @@ class AAudioLoader {

signature_U_PS stream_getChannelMask = nullptr;

signature_I_PS stream_getHardwareChannelCount = nullptr;
signature_I_PS stream_getHardwareSampleRate = nullptr;
signature_F_PS stream_getHardwareFormat = nullptr;

private:
AAudioLoader() {}
~AAudioLoader();
Expand Down
10 changes: 10 additions & 0 deletions src/aaudio/AudioStreamAAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,16 @@ Result AudioStreamAAudio::open() {
mChannelMask = static_cast<ChannelMask>(mLibLoader->stream_getChannelMask(mAAudioStream));
}

if (mLibLoader->stream_getHardwareChannelCount != nullptr) {
mHardwareChannelCount = mLibLoader->stream_getHardwareChannelCount(mAAudioStream);
}
if (mLibLoader->stream_getHardwareSampleRate != nullptr) {
mHardwareSampleRate = mLibLoader->stream_getHardwareSampleRate(mAAudioStream);
}
if (mLibLoader->stream_getHardwareFormat != nullptr) {
mHardwareFormat = static_cast<AudioFormat>(mLibLoader->stream_getHardwareFormat(mAAudioStream));
}

LOGD("AudioStreamAAudio.open() format=%d, sampleRate=%d, capacity = %d",
static_cast<int>(mFormat), static_cast<int>(mSampleRate),
static_cast<int>(mBufferCapacityInFrames));
Expand Down
12 changes: 12 additions & 0 deletions src/common/Utilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,18 @@ int getSdkVersion() {
return sCachedSdkVersion;
}

bool isAtLeastPreReleaseCodename(const std::string& codename) {
std::string buildCodename = getPropertyString("ro.build.version.codename");
// Special case "REL", which means the build is not a pre-release build.
if ("REL" == buildCodename) {
return false;
}

// Otherwise lexically compare them. Return true if the build codename is equal to or
// greater than the requested codename.
return buildCodename.compare(codename) >= 0;
}

int getChannelCountFromChannelMask(ChannelMask channelMask) {
return __builtin_popcount(static_cast<uint32_t>(channelMask));
}
Expand Down