aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Wu <85952307+robertwu1@users.noreply.github.com>2023-03-24 17:09:00 +0000
committerGitHub <noreply@github.com>2023-03-24 10:09:00 -0700
commit79f9d8fc52aa59091d8ecd7e2c3146a524261fb8 (patch)
tree18ecf1850e64845bc9c9906e46a4045d096289cb
parente54826cfdb2c9480ca0b7bb38f4558f1e99ad152 (diff)
downloadoboe-79f9d8fc52aa59091d8ecd7e2c3146a524261fb8.tar.gz
Add privacy sensitive mode for API 30+ (#1751)
-rw-r--r--include/oboe/AudioStreamBase.h17
-rw-r--r--include/oboe/AudioStreamBuilder.h25
-rw-r--r--include/oboe/Definitions.h26
-rw-r--r--src/aaudio/AAudioLoader.cpp18
-rw-r--r--src/aaudio/AAudioLoader.h14
-rw-r--r--src/aaudio/AudioStreamAAudio.cpp14
-rw-r--r--src/opensles/AudioStreamOpenSLES.cpp9
-rw-r--r--tests/testStreamOpen.cpp78
8 files changed, 197 insertions, 4 deletions
diff --git a/include/oboe/AudioStreamBase.h b/include/oboe/AudioStreamBase.h
index c0a582e9..b956f351 100644
--- a/include/oboe/AudioStreamBase.h
+++ b/include/oboe/AudioStreamBase.h
@@ -158,6 +158,20 @@ public:
SessionId getSessionId() const { return mSessionId; }
/**
+ * Return whether this input stream is marked as privacy sensitive.
+ *
+ * See AudioStreamBuilder_setPrivacySensitiveMode().
+ *
+ * Added in API level 30 to AAudio.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return PrivacySensitiveMode::Enabled if privacy sensitive,
+ * PrivacySensitiveMode::Disabled if not privacy sensitive, and
+ * PrivacySensitiveMode::Unspecified if API is not supported.
+ */
+ PrivacySensitiveMode getPrivacySensitiveMode() const { return mPrivacySensitiveMode; }
+
+ /**
* @return true if Oboe can convert channel counts to achieve optimal results.
*/
bool isChannelConversionAllowed() const {
@@ -244,6 +258,9 @@ protected:
/** Stream session ID allocation strategy. Only active on Android 28+ */
SessionId mSessionId = SessionId::None;
+ /** Privacy Sensitive Mode. Only active on Android 30+ */
+ PrivacySensitiveMode mPrivacySensitiveMode = PrivacySensitiveMode::Unspecified;
+
/** Control the name of the package creating the stream. Only active on Android 31+ */
std::string mPackageName;
/** Control the attribution tag of the context creating the stream. Only active on Android 31+ */
diff --git a/include/oboe/AudioStreamBuilder.h b/include/oboe/AudioStreamBuilder.h
index 5c7ac4b6..04e50292 100644
--- a/include/oboe/AudioStreamBuilder.h
+++ b/include/oboe/AudioStreamBuilder.h
@@ -348,6 +348,31 @@ public:
return this;
}
+
+ /** Indicates whether this input stream must be marked as privacy sensitive or not.
+ *
+ * When PrivacySensitiveMode::Enabled, this input stream is privacy sensitive and any
+ * concurrent capture is not permitted.
+ *
+ * This is off (PrivacySensitiveMode::Disabled) by default except when the input preset is
+ * InputPreset::VoiceRecognition or InputPreset::Camcorder
+ *
+ * Always takes precedence over default from input preset when set explicitly.
+ *
+ * Only relevant if the stream direction is Direction::Input and AAudio is used.
+ *
+ * Added in API level 30 to AAudio.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param privacySensitive PrivacySensitiveMode::Enabled if capture from this stream must be
+ * marked as privacy sensitive, PrivacySensitiveMode::Disabled if stream should be marked as
+ * not sensitive.
+ */
+ AudioStreamBuilder *setPrivacySensitiveMode(PrivacySensitiveMode privacySensitiveMode) {
+ mPrivacySensitiveMode = privacySensitiveMode;
+ return this;
+ }
+
/**
* Specifies an object to handle data related callbacks from the underlying API.
*
diff --git a/include/oboe/Definitions.h b/include/oboe/Definitions.h
index 763d1d2a..3cc4c03e 100644
--- a/include/oboe/Definitions.h
+++ b/include/oboe/Definitions.h
@@ -651,6 +651,32 @@ namespace oboe {
};
/**
+ * The PrivacySensitiveMode attribute determines whether an input stream can be shared
+ * with another privileged app, for example the Assistant.
+ *
+ * This allows to override the default behavior tied to the audio source (e.g
+ * InputPreset::VoiceCommunication is private by default but InputPreset::Unprocessed is not).
+ */
+ enum class PrivacySensitiveMode : int32_t {
+
+ /**
+ * When not explicitly requested, set privacy sensitive mode according to input preset:
+ * communication and camcorder captures are considered privacy sensitive by default.
+ */
+ Unspecified = kUnspecified,
+
+ /**
+ * Privacy sensitive mode disabled.
+ */
+ Disabled = 1,
+
+ /**
+ * Privacy sensitive mode enabled.
+ */
+ Enabled = 2,
+ };
+
+ /**
* On API 16 to 26 OpenSL ES will be used. When using OpenSL ES the optimal values for sampleRate and
* framesPerBurst are not known by the native code.
* On API 17+ these values should be obtained from the AudioManager using this code:
diff --git a/src/aaudio/AAudioLoader.cpp b/src/aaudio/AAudioLoader.cpp
index e873e5dd..6d9d6445 100644
--- a/src/aaudio/AAudioLoader.cpp
+++ b/src/aaudio/AAudioLoader.cpp
@@ -83,6 +83,10 @@ int AAudioLoader::open() {
builder_setSessionId = load_V_PBI("AAudioStreamBuilder_setSessionId");
}
+ if (getSdkVersion() >= __ANDROID_API_R__){
+ builder_setPrivacySensitive = load_V_PBO("AAudioStreamBuilder_setPrivacySensitive");
+ }
+
if (getSdkVersion() >= __ANDROID_API_S__){
builder_setPackageName = load_V_PBCPH("AAudioStreamBuilder_setPackageName");
builder_setAttributionTag = load_V_PBCPH("AAudioStreamBuilder_setAttributionTag");
@@ -147,6 +151,10 @@ int AAudioLoader::open() {
stream_getSessionId = load_I_PS("AAudioStream_getSessionId");
}
+ if (getSdkVersion() >= __ANDROID_API_R__){
+ stream_isPrivacySensitive = load_O_PS("AAudioStream_isPrivacySensitive");
+ }
+
if (getSdkVersion() >= __ANDROID_API_S_V2__) {
stream_getChannelMask = load_U_PS("AAudioStream_getChannelMask");
}
@@ -227,10 +235,10 @@ AAudioLoader::signature_F_PS AAudioLoader::load_F_PS(const char *functionName) {
return reinterpret_cast<signature_F_PS>(proc);
}
-AAudioLoader::signature_B_PS AAudioLoader::load_B_PS(const char *functionName) {
+AAudioLoader::signature_O_PS AAudioLoader::load_O_PS(const char *functionName) {
void *proc = dlsym(mLibHandle, functionName);
AAudioLoader_check(proc, functionName);
- return reinterpret_cast<signature_B_PS>(proc);
+ return reinterpret_cast<signature_O_PS>(proc);
}
AAudioLoader::signature_I_PB AAudioLoader::load_I_PB(const char *functionName) {
@@ -281,6 +289,12 @@ AAudioLoader::signature_U_PS AAudioLoader::load_U_PS(const char *functionName) {
return reinterpret_cast<signature_U_PS>(proc);
}
+AAudioLoader::signature_V_PBO AAudioLoader::load_V_PBO(const char *functionName) {
+ void *proc = dlsym(mLibHandle, functionName);
+ AAudioLoader_check(proc, functionName);
+ return reinterpret_cast<signature_V_PBO>(proc);
+}
+
// Ensure that all AAudio primitive data types are int32_t
#define ASSERT_INT32(type) static_assert(std::is_same<int32_t, type>::value, \
#type" must be int32_t")
diff --git a/src/aaudio/AAudioLoader.h b/src/aaudio/AAudioLoader.h
index cff0bea9..4114af9e 100644
--- a/src/aaudio/AAudioLoader.h
+++ b/src/aaudio/AAudioLoader.h
@@ -108,6 +108,8 @@ class AAudioLoader {
// C = Const prefix
// H = cHar
// U = uint32_t
+ // O = bOol
+
typedef int32_t (*signature_I_PPB)(AAudioStreamBuilder **builder);
typedef const char * (*signature_CPH_I)(int32_t);
@@ -124,6 +126,9 @@ class AAudioLoader {
typedef void (*signature_V_PBCPH)(AAudioStreamBuilder *, const char *);
+ // AAudioStreamBuilder_setPrivacySensitive
+ typedef void (*signature_V_PBO)(AAudioStreamBuilder *, bool);
+
typedef int32_t (*signature_I_PS)(AAudioStream *); // AAudioStream_getSampleRate()
typedef int64_t (*signature_L_PS)(AAudioStream *); // AAudioStream_getFramesRead()
// AAudioStream_setBufferSizeInFrames()
@@ -149,7 +154,7 @@ class AAudioLoader {
typedef int32_t (*signature_I_PSKPLPL)(AAudioStream *, clockid_t, int64_t *, int64_t *);
- typedef bool (*signature_B_PS)(AAudioStream *);
+ typedef bool (*signature_O_PS)(AAudioStream *);
typedef uint32_t (*signature_U_PS)(AAudioStream *);
@@ -189,6 +194,8 @@ class AAudioLoader {
signature_V_PBI builder_setInputPreset = nullptr;
signature_V_PBI builder_setSessionId = nullptr;
+ signature_V_PBO builder_setPrivacySensitive = nullptr;
+
signature_V_PBCPH builder_setPackageName = nullptr;
signature_V_PBCPH builder_setAttributionTag = nullptr;
@@ -237,6 +244,8 @@ class AAudioLoader {
signature_I_PS stream_getInputPreset = nullptr;
signature_I_PS stream_getSessionId = nullptr;
+ signature_O_PS stream_isPrivacySensitive = nullptr;
+
signature_U_PS stream_getChannelMask = nullptr;
signature_I_PS stream_getHardwareChannelCount = nullptr;
@@ -259,7 +268,7 @@ class AAudioLoader {
signature_I_PS load_I_PS(const char *name);
signature_L_PS load_L_PS(const char *name);
signature_F_PS load_F_PS(const char *name);
- signature_B_PS load_B_PS(const char *name);
+ signature_O_PS load_O_PS(const char *name);
signature_I_PSI load_I_PSI(const char *name);
signature_I_PSPVIL load_I_PSPVIL(const char *name);
signature_I_PSCPVIL load_I_PSCPVIL(const char *name);
@@ -267,6 +276,7 @@ class AAudioLoader {
signature_I_PSKPLPL load_I_PSKPLPL(const char *name);
signature_V_PBU load_V_PBU(const char *name);
signature_U_PS load_U_PS(const char *name);
+ signature_V_PBO load_V_PBO(const char *name);
void *mLibHandle = nullptr;
};
diff --git a/src/aaudio/AudioStreamAAudio.cpp b/src/aaudio/AudioStreamAAudio.cpp
index 46c76668..121bd525 100644
--- a/src/aaudio/AudioStreamAAudio.cpp
+++ b/src/aaudio/AudioStreamAAudio.cpp
@@ -263,6 +263,12 @@ Result AudioStreamAAudio::open() {
mAttributionTag.c_str());
}
+ if (mLibLoader->builder_setPrivacySensitive != nullptr && mDirection == oboe::Direction::Input
+ && mPrivacySensitiveMode != PrivacySensitiveMode::Unspecified) {
+ mLibLoader->builder_setPrivacySensitive(aaudioBuilder,
+ mPrivacySensitiveMode == PrivacySensitiveMode::Enabled);
+ }
+
if (isDataCallbackSpecified()) {
mLibLoader->builder_setDataCallback(aaudioBuilder, oboe_aaudio_data_callback_proc, this);
mLibLoader->builder_setFramesPerDataCallback(aaudioBuilder, getFramesPerDataCallback());
@@ -320,6 +326,14 @@ Result AudioStreamAAudio::open() {
mSessionId = SessionId::None;
}
+ if (mLibLoader->stream_isPrivacySensitive != nullptr && mDirection == oboe::Direction::Input) {
+ bool isPrivacySensitive = mLibLoader->stream_isPrivacySensitive(mAAudioStream);
+ mPrivacySensitiveMode = isPrivacySensitive ? PrivacySensitiveMode::Enabled :
+ PrivacySensitiveMode::Disabled;
+ } else {
+ mPrivacySensitiveMode = PrivacySensitiveMode::Unspecified;
+ }
+
if (mLibLoader->stream_getChannelMask != nullptr) {
mChannelMask = static_cast<ChannelMask>(mLibLoader->stream_getChannelMask(mAAudioStream));
}
diff --git a/src/opensles/AudioStreamOpenSLES.cpp b/src/opensles/AudioStreamOpenSLES.cpp
index 62692a42..8f730b01 100644
--- a/src/opensles/AudioStreamOpenSLES.cpp
+++ b/src/opensles/AudioStreamOpenSLES.cpp
@@ -108,6 +108,9 @@ Result AudioStreamOpenSLES::open() {
SLresult AudioStreamOpenSLES::finishCommonOpen(SLAndroidConfigurationItf configItf) {
+ // Setting privacy sensitive mode is not supported for OpenSL ES.
+ mPrivacySensitiveMode = PrivacySensitiveMode::Unspecified;
+
SLresult result = registerBufferQueueCallback();
if (SL_RESULT_SUCCESS != result) {
return result;
@@ -285,6 +288,12 @@ void AudioStreamOpenSLES::logUnsupportedAttributes() {
LOGW("SessionId [AudioStreamBuilder::setSessionId()] "
"is not supported on OpenSLES streams.");
}
+
+ // Privacy Sensitive Mode
+ if (mPrivacySensitiveMode != PrivacySensitiveMode::Unspecified) {
+ LOGW("PrivacySensitiveMode [AudioStreamBuilder::setPrivacySensitiveMode()] "
+ "is not supported on OpenSLES streams.");
+ }
}
SLresult AudioStreamOpenSLES::configurePerformanceMode(SLAndroidConfigurationItf configItf) {
diff --git a/tests/testStreamOpen.cpp b/tests/testStreamOpen.cpp
index 9d01c072..8eb97b94 100644
--- a/tests/testStreamOpen.cpp
+++ b/tests/testStreamOpen.cpp
@@ -460,3 +460,81 @@ TEST_F(StreamOpenOutput, OboeExtensions){
ASSERT_TRUE(OboeExtensions::isMMapEnabled());
}
}
+
+TEST_F(StreamOpenInput, AAudioInputSetPrivacySensitiveModeUnspecifiedUnprocessed){
+ if (getSdkVersion() >= __ANDROID_API_R__){
+ mBuilder.setDirection(Direction::Input);
+ mBuilder.setAudioApi(AudioApi::AAudio);
+ mBuilder.setInputPreset(InputPreset::Unprocessed);
+ ASSERT_TRUE(openStream());
+ ASSERT_EQ(mStream->getPrivacySensitiveMode(), PrivacySensitiveMode::Disabled);
+ ASSERT_TRUE(closeStream());
+ }
+}
+
+TEST_F(StreamOpenInput, AAudioInputSetPrivacySensitiveModeUnspecifiedVoiceCommunication){
+ if (getSdkVersion() >= __ANDROID_API_R__){
+ mBuilder.setDirection(Direction::Input);
+ mBuilder.setAudioApi(AudioApi::AAudio);
+ mBuilder.setInputPreset(InputPreset::VoiceCommunication);
+ ASSERT_TRUE(openStream());
+ ASSERT_EQ(mStream->getPrivacySensitiveMode(), PrivacySensitiveMode::Enabled);
+ ASSERT_TRUE(closeStream());
+ }
+}
+
+TEST_F(StreamOpenInput, AAudioInputSetPrivacySensitiveModeVoiceDisabled){
+ if (getSdkVersion() >= __ANDROID_API_R__){
+ mBuilder.setDirection(Direction::Input);
+ mBuilder.setAudioApi(AudioApi::AAudio);
+ mBuilder.setInputPreset(InputPreset::VoiceCommunication);
+ mBuilder.setPrivacySensitiveMode(PrivacySensitiveMode::Disabled);
+ ASSERT_TRUE(openStream());
+ ASSERT_EQ(mStream->getPrivacySensitiveMode(), PrivacySensitiveMode::Disabled);
+ ASSERT_TRUE(closeStream());
+ }
+}
+
+TEST_F(StreamOpenInput, AAudioInputSetPrivacySensitiveModeUnprocessedEnabled){
+ if (getSdkVersion() >= __ANDROID_API_R__){
+ mBuilder.setDirection(Direction::Input);
+ mBuilder.setAudioApi(AudioApi::AAudio);
+ mBuilder.setInputPreset(InputPreset::Unprocessed);
+ mBuilder.setPrivacySensitiveMode(PrivacySensitiveMode::Enabled);
+ ASSERT_TRUE(openStream());
+ ASSERT_EQ(mStream->getPrivacySensitiveMode(), PrivacySensitiveMode::Enabled);
+ ASSERT_TRUE(closeStream());
+ }
+}
+
+TEST_F(StreamOpenOutput, AAudioOutputSetPrivacySensitiveModeGetsUnspecified){
+ if (getSdkVersion() >= __ANDROID_API_R__){
+ mBuilder.setDirection(Direction::Output);
+ mBuilder.setAudioApi(AudioApi::AAudio);
+ mBuilder.setPrivacySensitiveMode(PrivacySensitiveMode::Enabled);
+ ASSERT_TRUE(openStream());
+ ASSERT_EQ(mStream->getPrivacySensitiveMode(), PrivacySensitiveMode::Unspecified);
+ ASSERT_TRUE(closeStream());
+ }
+}
+
+TEST_F(StreamOpenInput, OpenSLESInputSetPrivacySensitiveModeDoesNotCrash){
+ mBuilder.setDirection(Direction::Input);
+ mBuilder.setAudioApi(AudioApi::OpenSLES);
+ mBuilder.setInputPreset(InputPreset::Unprocessed);
+ mBuilder.setPrivacySensitiveMode(PrivacySensitiveMode::Enabled);
+ ASSERT_TRUE(openStream());
+ ASSERT_EQ(mStream->getPrivacySensitiveMode(), PrivacySensitiveMode::Unspecified);
+ ASSERT_TRUE(closeStream());
+}
+
+TEST_F(StreamOpenInput, OldAndroidVersionInputSetPrivacySensitiveModeDoesNotCrash){
+ if (getSdkVersion() < __ANDROID_API_R__) {
+ mBuilder.setDirection(Direction::Input);
+ mBuilder.setInputPreset(InputPreset::Unprocessed);
+ mBuilder.setPrivacySensitiveMode(PrivacySensitiveMode::Enabled);
+ ASSERT_TRUE(openStream());
+ ASSERT_EQ(mStream->getPrivacySensitiveMode(), PrivacySensitiveMode::Unspecified);
+ ASSERT_TRUE(closeStream());
+ }
+}