Add explicit private audio recording request
Add the possibility for apps to indicate that their
capture use case is private and that a privileged Assistant
should not be able to capture concurrently.
This allows to override the default behavior tied to the audio
source (e.g VOICE_COMMUNICATION is private by default but
UNPROCESSED is not).
- Add AAudio API to set and get privacy sensitive mode on input stream
- Add MediaRecorder API to set and get privacy sensitive mode
- Modify AudioSource constructor to accept audio attributes instead of an
audio source to specify the use case.
- Modify audio policy concurrent capture logic to use audio attributes
flag instead of audio source to decide of a capture client has
requested privacy mode or not.
Bug: 137850106
Test: CTS AudioRecordTest and MediaRecorderTest, manual audio smoke tests
Change-Id: I250ea5da4c1da809ceac0da22ae9bee15b937001
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index 9115778..4bba436 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -38,12 +38,15 @@
aaudio_input_preset_t inputPreset) = nullptr;
static void (*s_setAllowedCapturePolicy)(AAudioStreamBuilder* builder,
aaudio_allowed_capture_policy_t usage) = nullptr;
+static void (*s_setPrivacySensitive)(AAudioStreamBuilder* builder,
+ bool privacySensitive) = nullptr;
static bool s_loadAttempted = false;
static aaudio_usage_t (*s_getUsage)(AAudioStream *stream) = nullptr;
static aaudio_content_type_t (*s_getContentType)(AAudioStream *stream) = nullptr;
static aaudio_input_preset_t (*s_getInputPreset)(AAudioStream *stream) = nullptr;
static aaudio_allowed_capture_policy_t (*s_getAllowedCapturePolicy)(AAudioStream *stream) = nullptr;
+static bool (*s_isPrivacySensitive)(AAudioStream *stream) = nullptr;
// Link to test functions in shared library.
static void loadFutureFunctions() {
@@ -68,6 +71,10 @@
dlsym(handle, "AAudioStreamBuilder_setAllowedCapturePolicy");
if (s_setAllowedCapturePolicy == nullptr) goto error;
+ s_setPrivacySensitive = (void (*)(AAudioStreamBuilder *, bool))
+ dlsym(handle, "AAudioStreamBuilder_setPrivacySensitive");
+ if (s_setPrivacySensitive == nullptr) goto error;
+
s_getUsage = (aaudio_usage_t (*)(AAudioStream *))
dlsym(handle, "AAudioStream_getUsage");
if (s_getUsage == nullptr) goto error;
@@ -83,6 +90,10 @@
s_getAllowedCapturePolicy = (aaudio_input_preset_t (*)(AAudioStream *))
dlsym(handle, "AAudioStream_getAllowedCapturePolicy");
if (s_getAllowedCapturePolicy == nullptr) goto error;
+
+ s_isPrivacySensitive = (bool (*)(AAudioStream *))
+ dlsym(handle, "AAudioStream_isPrivacySensitive");
+ if (s_isPrivacySensitive == nullptr) goto error;
}
return;
@@ -91,9 +102,11 @@
s_setUsage = nullptr;
s_setContentType = nullptr;
s_setInputPreset = nullptr;
+ s_setPrivacySensitive = nullptr;
s_getUsage = nullptr;
s_getContentType = nullptr;
s_getInputPreset = nullptr;
+ s_isPrivacySensitive = nullptr;
dlclose(handle);
return;
}
@@ -211,6 +224,14 @@
mFramesPerCallback = size;
}
+ int32_t isPrivacySensitive() const {
+ return mPrivacySensitive;
+ }
+
+ void setPrivacySensitive(int32_t privacySensitive) {
+ mPrivacySensitive = privacySensitive;
+ }
+
/**
* Apply these parameters to a stream builder.
* @param builder
@@ -234,12 +255,12 @@
}
if (s_setContentType != nullptr) {
s_setContentType(builder, mContentType);
- } else if (mUsage != AAUDIO_UNSPECIFIED){
+ } else if (mContentType != AAUDIO_UNSPECIFIED){
printf("WARNING: setContentType not supported");
}
if (s_setInputPreset != nullptr) {
s_setInputPreset(builder, mInputPreset);
- } else if (mUsage != AAUDIO_UNSPECIFIED){
+ } else if (mInputPreset != AAUDIO_UNSPECIFIED){
printf("WARNING: setInputPreset not supported");
}
@@ -249,6 +270,15 @@
} else if (mAllowedCapturePolicy != AAUDIO_UNSPECIFIED){
printf("WARNING: setAllowedCapturePolicy not supported");
}
+
+ if (mPrivacySensitive != PRIVACY_SENSITIVE_DEFAULT) {
+ if (s_setPrivacySensitive != nullptr) {
+ s_setPrivacySensitive(builder,
+ mPrivacySensitive == PRIVACY_SENSITIVE_ENABLED);
+ } else {
+ printf("WARNING: setPrivacySensitive not supported");
+ }
+ }
}
static constexpr int32_t kDefaultNumberOfBursts = 2;
@@ -270,6 +300,13 @@
int32_t mNumberOfBursts = kDefaultNumberOfBursts;
int32_t mFramesPerCallback = AAUDIO_UNSPECIFIED;
+
+ enum {
+ PRIVACY_SENSITIVE_DEFAULT = -1,
+ PRIVACY_SENSITIVE_DISABLED = 0,
+ PRIVACY_SENSITIVE_ENABLED = 1,
+ };
+ int32_t mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
};
class AAudioArgsParser : public AAudioParameters {
@@ -341,6 +378,9 @@
case 'z':
setFramesPerCallback(atoi(&arg[2]));
break;
+ case 'S':
+ setPrivacySensitive(atoi(&arg[2]));
+ break;
default:
unrecognized = true;
break;
@@ -399,6 +439,9 @@
printf(" -x to use EXCLUSIVE mode\n");
printf(" -y{contentType} eg. 1 for AAUDIO_CONTENT_TYPE_SPEECH\n");
printf(" -z{callbackSize} or block size, in frames, default = 0\n");
+ printf(" -S{0|1} set privacy Sensitive enabled or disabled\n");
+ printf(" 0 = disabled\n");
+ printf(" 1 = enabled\n");
}
static aaudio_performance_mode_t parseAllowedCapturePolicy(char c) {
@@ -506,10 +549,15 @@
getContentType(), s_getContentType(stream));
}
- if (AAudioStream_getDirection(stream) == AAUDIO_DIRECTION_INPUT
- && s_getInputPreset != nullptr) {
+ if (AAudioStream_getDirection(stream) == AAUDIO_DIRECTION_INPUT) {
+ if (s_getInputPreset != nullptr) {
printf(" InputPreset: requested = %d, actual = %d\n",
getInputPreset(), s_getInputPreset(stream));
+ }
+ if (s_isPrivacySensitive != nullptr) {
+ printf(" Privacy Sensitive: requested = %d, actual = %d\n",
+ isPrivacySensitive(), s_isPrivacySensitive(stream));
+ }
}
printf(" Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index a4322a1..5bebd61 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -759,6 +759,28 @@
AAUDIO_API void AAudioStreamBuilder_setSessionId(AAudioStreamBuilder* builder,
aaudio_session_id_t sessionId) __INTRODUCED_IN(28);
+
+/** Indicates whether this input stream must be marked as privacy sensitive or not.
+ *
+ * When true, this input stream is privacy sensitive and any concurrent capture
+ * is not permitted.
+ *
+ * This is off (false) by default except when the input preset is {@link #AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION}
+ * or {@link #AAUDIO_INPUT_PRESET_CAMCORDER}.
+ *
+ * Always takes precedence over default from input preset when set explicitly.
+ *
+ * Only relevant if the stream direction is {@link #AAUDIO_DIRECTION_INPUT}.
+ *
+ * Added in API level 30.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ * @param privacySensitive true if capture from this stream must be marked as privacy sensitive,
+ * false otherwise.
+ */
+AAUDIO_API void AAudioStreamBuilder_setPrivacySensitive(AAudioStreamBuilder* builder,
+ bool privacySensitive) __INTRODUCED_IN(30);
+
/**
* Return one of these values from the data callback function.
*/
@@ -1444,6 +1466,20 @@
AAUDIO_API aaudio_allowed_capture_policy_t AAudioStream_getAllowedCapturePolicy(
AAudioStream* stream) __INTRODUCED_IN(29);
+
+/**
+ * Return whether this input stream is marked as privacy sensitive or not.
+ *
+ * See {@link #AAudioStreamBuilder_setPrivacySensitive()}.
+ *
+ * Added in API level 30.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return true if privacy sensitive, false otherwise
+ */
+AAUDIO_API bool AAudioStream_isPrivacySensitive(AAudioStream* stream)
+ __INTRODUCED_IN(30);
+
#ifdef __cplusplus
}
#endif
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index a987fab..b785f88 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -66,6 +66,8 @@
if (status != NO_ERROR) goto error;
status = parcel->writeInt32(getSessionId());
if (status != NO_ERROR) goto error;
+ status = parcel->writeInt32(isPrivacySensitive() ? 1 : 0);
+ if (status != NO_ERROR) goto error;
return NO_ERROR;
error:
ALOGE("%s(): write failed = %d", __func__, status);
@@ -111,7 +113,9 @@
status = parcel->readInt32(&value);
if (status != NO_ERROR) goto error;
setSessionId(value);
-
+ status = parcel->readInt32(&value);
+ if (status != NO_ERROR) goto error;
+ setPrivacySensitive(value == 1);
return NO_ERROR;
error:
ALOGE("%s(): read failed = %d", __func__, status);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 7481daa..bfad254 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -116,6 +116,7 @@
request.getConfiguration().setUsage(getUsage());
request.getConfiguration().setContentType(getContentType());
request.getConfiguration().setInputPreset(getInputPreset());
+ request.getConfiguration().setPrivacySensitive(isPrivacySensitive());
request.getConfiguration().setBufferCapacity(builder.getBufferCapacity());
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 8040e6a..184e9cb 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -149,6 +149,12 @@
streamBuilder->setInputPreset(inputPreset);
}
+AAUDIO_API void AAudioStreamBuilder_setPrivacySensitive(AAudioStreamBuilder* builder,
+ bool privacySensitive) {
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->setPrivacySensitiveRequest(privacySensitive);
+}
+
AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
int32_t frames)
{
@@ -507,3 +513,9 @@
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
return audioStream->isMMap();
}
+
+AAUDIO_API bool AAudioStream_isPrivacySensitive(AAudioStream* stream)
+{
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ return audioStream->isPrivacySensitive();
+}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index c9711da..58058f5 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -47,6 +47,7 @@
mContentType = other.mContentType;
mInputPreset = other.mInputPreset;
mAllowedCapturePolicy = other.mAllowedCapturePolicy;
+ mIsPrivacySensitive = other.mIsPrivacySensitive;
}
static aaudio_result_t isFormatValid(audio_format_t format) {
@@ -195,4 +196,5 @@
ALOGD("mContentType = %6d", mContentType);
ALOGD("mInputPreset = %6d", mInputPreset);
ALOGD("mAllowedCapturePolicy = %6d", mAllowedCapturePolicy);
+ ALOGD("mIsPrivacySensitive = %s", mIsPrivacySensitive ? "true" : "false");
}
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index 2e21a8d..3e65b37 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -128,6 +128,14 @@
mSessionId = sessionId;
}
+ bool isPrivacySensitive() const {
+ return mIsPrivacySensitive;
+ }
+
+ void setPrivacySensitive(bool privacySensitive) {
+ mIsPrivacySensitive = privacySensitive;
+ }
+
/**
* @return bytes per frame of getFormat()
*/
@@ -158,6 +166,7 @@
int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_UNSPECIFIED;
aaudio_session_id_t mSessionId = AAUDIO_SESSION_ID_NONE;
+ bool mIsPrivacySensitive = false;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 5303631..d928222 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -91,6 +91,7 @@
if (mAllowedCapturePolicy == AAUDIO_UNSPECIFIED) {
mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
}
+ mIsPrivacySensitive = builder.isPrivacySensitive();
// callbacks
mFramesPerDataCallback = builder.getFramesPerDataCallback();
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 044c979..b4ffcf2 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -234,6 +234,10 @@
return mSessionId;
}
+ bool isPrivacySensitive() const {
+ return mIsPrivacySensitive;
+ }
+
/**
* This is only valid after setSamplesPerFrame() and setFormat() have been called.
*/
@@ -543,6 +547,13 @@
mAllowedCapturePolicy = policy;
}
+ /**
+ * This should not be called after the open() call.
+ */
+ void setPrivacySensitive(bool privacySensitive) {
+ mIsPrivacySensitive = privacySensitive;
+ }
+
private:
aaudio_result_t safeStop();
@@ -565,6 +576,7 @@
aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED;
aaudio_input_preset_t mInputPreset = AAUDIO_UNSPECIFIED;
aaudio_allowed_capture_policy_t mAllowedCapturePolicy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
+ bool mIsPrivacySensitive = false;
int32_t mSessionId = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 44f45b3..af28a59 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -158,6 +158,19 @@
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
+ setPrivacySensitive(false);
+ if (mPrivacySensitiveReq == PRIVACY_SENSITIVE_DEFAULT) {
+ // When not explicitly requested, set privacy sensitive mode according to input preset:
+ // communication and camcorder captures are considered privacy sensitive by default.
+ aaudio_input_preset_t preset = getInputPreset();
+ if (preset == AAUDIO_INPUT_PRESET_CAMCORDER
+ || preset == AAUDIO_INPUT_PRESET_VOICE_COMMUNICATION) {
+ setPrivacySensitive(true);
+ }
+ } else if (mPrivacySensitiveReq == PRIVACY_SENSITIVE_ENABLED) {
+ setPrivacySensitive(true);
+ }
+
result = builder_createStream(getDirection(), sharingMode, allowMMap, &audioStream);
if (result == AAUDIO_OK) {
// Open the stream using the parameters from the builder.
@@ -257,4 +270,5 @@
mFramesPerDataCallback);
ALOGI("usage = %6d, contentType = %d, inputPreset = %d, allowedCapturePolicy = %d",
getUsage(), getContentType(), getInputPreset(), getAllowedCapturePolicy());
+ ALOGI("privacy sensitive = %s", isPrivacySensitive() ? "true" : "false");
}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index 8149af2..d5fb80d 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -98,6 +98,12 @@
return this;
}
+ AudioStreamBuilder* setPrivacySensitiveRequest(bool privacySensitive) {
+ mPrivacySensitiveReq =
+ privacySensitive ? PRIVACY_SENSITIVE_ENABLED : PRIVACY_SENSITIVE_DISABLED;
+ return this;
+ }
+
aaudio_result_t build(AudioStream **streamPtr);
virtual aaudio_result_t validate() const override;
@@ -114,6 +120,14 @@
AAudioStream_errorCallback mErrorCallbackProc = nullptr;
void *mErrorCallbackUserData = nullptr;
+
+ enum {
+ PRIVACY_SENSITIVE_DEFAULT = -1,
+ PRIVACY_SENSITIVE_DISABLED = 0,
+ PRIVACY_SENSITIVE_ENABLED = 1,
+ };
+ typedef int32_t privacy_sensitive_t;
+ privacy_sensitive_t mPrivacySensitiveReq = PRIVACY_SENSITIVE_DEFAULT;
};
} /* namespace aaudio */
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 71efc30..54af580 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -142,11 +142,13 @@
const audio_source_t source =
AAudioConvert_inputPresetToAudioSource(builder.getInputPreset());
+ const audio_flags_mask_t attrFlags =
+ AAudioConvert_privacySensitiveToAudioFlagsMask(builder.isPrivacySensitive());
const audio_attributes_t attributes = {
.content_type = contentType,
.usage = AUDIO_USAGE_UNKNOWN, // only used for output
.source = source,
- .flags = AUDIO_FLAG_NONE, // Different than the AUDIO_INPUT_FLAGS
+ .flags = attrFlags, // Different than the AUDIO_INPUT_FLAGS
.tags = ""
};
diff --git a/media/libaaudio/src/utility/AAudioUtilities.cpp b/media/libaaudio/src/utility/AAudioUtilities.cpp
index c2f7fd0..ef89697 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.cpp
+++ b/media/libaaudio/src/utility/AAudioUtilities.cpp
@@ -234,6 +234,11 @@
}
}
+audio_flags_mask_t AAudioConvert_privacySensitiveToAudioFlagsMask(
+ bool privacySensitive) {
+ return privacySensitive ? AUDIO_FLAG_CAPTURE_PRIVATE : AUDIO_FLAG_NONE;
+}
+
int32_t AAudioConvert_framesToBytes(int32_t numFrames,
int32_t bytesPerFrame,
int32_t *sizeInBytes) {
diff --git a/media/libaaudio/src/utility/AAudioUtilities.h b/media/libaaudio/src/utility/AAudioUtilities.h
index 5dcddf3..d2e4805 100644
--- a/media/libaaudio/src/utility/AAudioUtilities.h
+++ b/media/libaaudio/src/utility/AAudioUtilities.h
@@ -92,6 +92,9 @@
audio_flags_mask_t AAudioConvert_allowCapturePolicyToAudioFlagsMask(
aaudio_allowed_capture_policy_t policy);
+audio_flags_mask_t AAudioConvert_privacySensitiveToAudioFlagsMask(
+ bool privacySensitive);
+
// Note that this code may be replaced by Settings or by some other system configuration tool.
/**