Merge "Preserve previous control parameters with common AIDL parameter setting" into main
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index af82982..a1413b7 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -130,6 +130,7 @@
namespace: "codec_fwk"
description: "Feature flag for exposing number of input slots"
bug: "159891571"
+ is_exported: true
}
flag {
@@ -207,6 +208,7 @@
namespace: "codec_fwk"
description: "Feature flag for subsession codec metrics"
bug: "363382811"
+ is_exported: true
}
flag {
diff --git a/media/aconfig/mediacodec_flags.aconfig b/media/aconfig/mediacodec_flags.aconfig
index 3cc9a1a..2679920 100644
--- a/media/aconfig/mediacodec_flags.aconfig
+++ b/media/aconfig/mediacodec_flags.aconfig
@@ -26,4 +26,5 @@
namespace: "codec_fwk"
description: "Feature flags for large audio frame support"
bug: "297219557"
+ is_exported: true
}
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 1450417..d157a97 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -30,6 +30,7 @@
"New privileged permission to allow bypassing concurrent audio"
"capture rules."
bug: "374751406"
+ is_exported: true
}
flag {
@@ -82,6 +83,7 @@
description: "Feature flag for Dolby AC-4 level 4 AudioFormat encoding."
is_fixed_read_only: true
bug: "266537650"
+ is_exported: true
}
# TODO remove
@@ -158,6 +160,7 @@
namespace: "media_audio"
description: "Playback monitoring flag used when player muted by port volume"
bug: "319515324"
+ is_exported: true
}
flag {
@@ -204,6 +207,7 @@
"Enable Java and native functions to get"
"multiple routed device ids"
bug: "367816690"
+ is_exported: true
}
flag {
@@ -218,6 +222,7 @@
namespace: "media_audio"
description: "spatializer reports effective channel masks"
bug: "377582613"
+ is_exported: true
}
flag {
@@ -225,6 +230,7 @@
namespace: "media_audio"
description: "Support new AudioAttributes usage for speaker cleanup"
bug: "355050846"
+ is_exported: true
}
flag {
@@ -232,6 +238,7 @@
namespace: "media_audio"
description: "Surface new API method for returning speaker layout channel mask for devices"
bug: "337522902"
+ is_exported: true
}
# TODO remove
diff --git a/media/codec2/hal/client/ApexCodecsLazy.cpp b/media/codec2/hal/client/ApexCodecsLazy.cpp
index 2db4cb1..cd7953e 100644
--- a/media/codec2/hal/client/ApexCodecsLazy.cpp
+++ b/media/codec2/hal/client/ApexCodecsLazy.cpp
@@ -64,6 +64,11 @@
public:
ApexCodecsLazyLoader() = default;
+ static ApexCodecsLazyLoader &Get() {
+ static ::android::base::NoDestructor<ApexCodecsLazyLoader> sLoader;
+ return *sLoader;
+ }
+
void *getMethodAt(enum MethodIndex index) {
RWLock::AutoRLock l(mLock);
if (mInit) {
@@ -79,11 +84,6 @@
}
private:
- RWLock mLock;
- // Table of methods pointers in libapexcodecs APIs.
- void* mMethods[k_MethodCount];
- bool mInit{false};
-
static void* LoadLibapexcodecs(int dlopen_flags) {
return dlopen("libapexcodecs.so", dlopen_flags);
}
@@ -144,20 +144,20 @@
mInit = true;
return true;
}
-};
-static ApexCodecsLazyLoader &GetLoader() {
- ::android::base::NoDestructor<ApexCodecsLazyLoader> sLoader;
- return *sLoader;
-}
+ RWLock mLock;
+ // Table of methods pointers in libapexcodecs APIs.
+ void* mMethods[k_MethodCount];
+ bool mInit{false};
+};
} // anonymous namespace
-#define INVOKE_METHOD(name, returnIfNull, args...) \
- do { \
- void* method = GetLoader().getMethodAt(k_##name); \
- if (!method) return (returnIfNull); \
- return reinterpret_cast<decltype(&name)>(method)(args); \
+#define INVOKE_METHOD(name, returnIfNull, args...) \
+ do { \
+ void* method = ApexCodecsLazyLoader::Get().getMethodAt(k_##name); \
+ if (!method) return (returnIfNull); \
+ return reinterpret_cast<decltype(&name)>(method)(args); \
} while (0)
//
diff --git a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
index c3b43ab..07fed18 100644
--- a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
+++ b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
@@ -25,6 +25,7 @@
constexpr int32_t kRandomStringLength = 256;
constexpr int32_t kMaxRuns = 100;
constexpr int64_t kNanosPerMillisecond = 1000 * 1000;
+constexpr int32_t kAAudioAttributesTagsMaxSize = 256;
constexpr aaudio_direction_t kDirections[] = {
AAUDIO_DIRECTION_OUTPUT, AAUDIO_DIRECTION_INPUT, AAUDIO_UNSPECIFIED};
@@ -185,10 +186,10 @@
AAudioStreamBuilder_setFramesPerDataCallback(mAaudioBuilder, framesPerDataCallback);
const size_t tagsNumBytes = fdp.ConsumeIntegralInRange<size_t>(
- 0, AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE + 10);
- AAudioStreamBuilder_setTags(mAaudioBuilder,
- (tagsNumBytes == 0 ? nullptr
- : fdp.ConsumeBytesAsString(tagsNumBytes).c_str()));
+ 0, kAAudioAttributesTagsMaxSize + 10);
+ AAudioStreamBuilder_addTag(mAaudioBuilder,
+ (tagsNumBytes == 0 ? nullptr
+ : fdp.ConsumeBytesAsString(tagsNumBytes).c_str()));
aaudio_policy_t policy =
fdp.PickValueInArray({fdp.PickValueInArray(kPolicies), fdp.ConsumeIntegral<int32_t>()});
@@ -200,7 +201,7 @@
int32_t maxFrames = 0;
int32_t count = 0;
aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
- char tags[AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE + 1];
+ int numOfTags = 0;
invokeAAudioSetAPIs(fdp);
@@ -320,7 +321,9 @@
(void)AAudioStream_getBufferSizeInFrames(mAaudioStream);
},
[&]() {
- (void)AAudioStream_getTags(mAaudioStream, tags);
+ char** tags = nullptr;
+ (void)AAudioStream_obtainTags(mAaudioStream, &tags);
+ AAudioStream_releaseTags(mAaudioStream, tags);
},
[&]() {
(void)AAudioStream_isMMapUsed(mAaudioStream);
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index c3e7583..e72685c 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -2571,6 +2571,34 @@
AAUDIO_API aaudio_policy_t AAudio_getPlatformMMapExclusivePolicy(
AAudio_DeviceType device, aaudio_direction_t direction) __INTRODUCED_IN(36);
+/**
+ * Control whether AAudioStreamBuilder_openStream() will use the new MMAP data path
+ * or the older "Legacy" data path.
+ *
+ * This will only affect the current process.
+ *
+ * If unspecified then the policy will be based on system properties or configuration.
+ *
+ * @param policy {@link #AAUDIO_UNSPECIFIED}, {@link #AAUDIO_POLICY_NEVER},
+ * {@link #AAUDIO_POLICY_AUTO}, or {@link #AAUDIO_POLICY_ALWAYS}
+ * @return AAUDIO_OK or a negative error
+ */
+AAUDIO_API aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy) __INTRODUCED_IN(36);
+
+/**
+ * Get the current MMAP policy set by AAudio_setMMapPolicy().
+ *
+ * @return current policy or {@link #AAUDIO_UNSPECIFIED} if it is never set.
+ */
+AAUDIO_API aaudio_policy_t AAudio_getMMapPolicy() __INTRODUCED_IN(36);
+
+/**
+ * Return true if the stream uses the MMAP data path versus the legacy path.
+ *
+ * @return true if the stream uses the MMAP data path
+ */
+AAUDIO_API bool AAudioStream_isMMapUsed(AAudioStream* _Nonnull stream) __INTRODUCED_IN(36);
+
#ifdef __cplusplus
}
#endif
diff --git a/media/libaaudio/include/aaudio/AAudioTesting.h b/media/libaaudio/include/aaudio/AAudioTesting.h
index 8758e07..842a2db 100644
--- a/media/libaaudio/include/aaudio/AAudioTesting.h
+++ b/media/libaaudio/include/aaudio/AAudioTesting.h
@@ -22,55 +22,10 @@
#include <aaudio/AAudio.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/************************************************************************************
- * The definitions below are only for testing. Do not use them in an application.
- * They may change or be removed at any time.
+ * These MMap functions were moved to AAudio.h
************************************************************************************/
-/**
- * Control whether AAudioStreamBuilder_openStream() will use the new MMAP data path
- * or the older "Legacy" data path.
- *
- * This will only affect the current process.
- *
- * If unspecified then the policy will be based on system properties or configuration.
- *
- * @note This is only for testing. Do not use this in an application.
- * It may change or be removed at any time.
- *
- * @param policy AAUDIO_UNSPECIFIED, AAUDIO_POLICY_NEVER, AAUDIO_POLICY_AUTO, or AAUDIO_POLICY_ALWAYS
- * @return AAUDIO_OK or a negative error
- */
-AAUDIO_API aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);
-
-/**
- * Get the current MMAP policy set by AAudio_setMMapPolicy().
- *
- * @note This is only for testing. Do not use this in an application.
- * It may change or be removed at any time.
- *
- * @return current policy
- */
-AAUDIO_API aaudio_policy_t AAudio_getMMapPolicy();
-
-/**
- * Return true if the stream uses the MMAP data path versus the legacy path.
- *
- * @note This is only for testing. Do not use this in an application.
- * It may change or be removed at any time.
- *
- * @return true if the stream uses the MMAP data path
- */
-AAUDIO_API bool AAudioStream_isMMapUsed(AAudioStream* stream);
-
-#ifdef __cplusplus
-}
-#endif
-
#endif //AAUDIO_AAUDIO_TESTING_H
/** @} */
diff --git a/media/libaaudio/include/system/aaudio/AAudio.h b/media/libaaudio/include/system/aaudio/AAudio.h
index 933ad35..4c2d291 100644
--- a/media/libaaudio/include/system/aaudio/AAudio.h
+++ b/media/libaaudio/include/system/aaudio/AAudio.h
@@ -27,51 +27,62 @@
#endif
/**
- * The tags string attributes allows OEMs to extend the
- * <a href="/reference/android/media/AudioAttributes">AudioAttributes</a>.
+ * Add one vendor extension tag that the output stream will carry.
*
- * Note that the maximum length includes all tags combined with delimiters and null terminator.
+ * The total size of all added tags, plus one for each tag terminator, must not be greater than
+ * <a href="/reference/android/system/media/audio">AUDIO_ATTRIBUTES_TAGS_MAX_SIZE</a>.
*
- * Note that it matches the equivalent value in
- * <a href="/reference/android/system/media/audio">AUDIO_ATTRIBUTES_TAGS_MAX_SIZE</a>
- * in the Android native API.
- */
-#define AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE 256
-
-/**
- * Set one or more vendor extension tags that the output stream will carry.
- *
- * The tags can be used by the audio policy engine for routing purpose.
+ * The tag can be used by the audio policy engine for routing purpose.
* Routing is based on audio attributes, translated into legacy stream type.
* The stream types cannot be extended, so the product strategies have been introduced to allow
* vendor extension of routing capabilities.
* This could, for example, affect how volume and routing is handled for the stream.
*
- * The tags can also be used by a System App to pass vendor specific information through the
+ * The tag can also be used by a System App to pass vendor specific information through the
* framework to the HAL. That info could affect routing, ducking or other audio behavior in the HAL.
*
* By default, audio attributes tags are empty if this method is not called.
*
+ * When opening a stream with audio attributes tags, the client should hold
+ * MODIFY_AUDIO_SETTINGS_PRIVILEGED permission. Otherwise, the stream will fail to open.
+ *
* @param builder reference provided by AAudio_createStreamBuilder()
- * @param tags the desired tags to add, which must be UTF-8 format and null-terminated. The size
- * of the tags must be at most {@link #AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE}. Multiple tags
- * must be separated by semicolons.
+ * @param tag the desired tag to add, which must be UTF-8 format and null-terminated.
* @return {@link #AAUDIO_OK} on success or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if the given
- * tags is null or its length is greater than {@link #AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE}.
+ * tags is null or {@link #AAUDIO_ERROR_OUT_OF_RANGE} if there is not room for more tags.
*/
-aaudio_result_t AAudioStreamBuilder_setTags(AAudioStreamBuilder* _Nonnull builder,
- const char* _Nonnull tags);
+aaudio_result_t AAudioStreamBuilder_addTag(AAudioStreamBuilder* _Nonnull builder,
+ const char* _Nonnull tag);
/**
- * Read the audio attributes' tags for the stream into a buffer.
- * The caller is responsible for allocating and freeing the returned data.
+ * Clear all the tags that has been added from calling
+ * {@link #AAudioStreamBuilder_addTag}.
+ *
+ * @param builder reference provided by AAudio_createStreamBuilder()
+ */
+void AAudioStreamBuilder_clearTags(AAudioStreamBuilder* _Nonnull builder);
+
+/**
+ * Allocate and read the audio attributes' tags for the stream into a buffer.
+ * The client is responsible to free the memory for tags by calling
+ * {@link #AAudioStream_releaseTags} unless the number of tags is 0.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
- * @param tags pointer to write the value to in UTF-8 that containing OEM extension tags. It must
- * be sized with {@link #AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE}.
- * @return {@link #AAUDIO_OK} or {@link #AAUDIO_ERROR_ILLEGAL_ARGUMENT} if the given tags is null.
+ * @param tags a pointer to a variable that will be set to a pointer to an array of char* pointers
+ * @return number of tags or
+ * {@link #AAUDIO_ERROR_NO_MEMORY} if it fails to allocate memory for tags.
*/
-aaudio_result_t AAudioStream_getTags(AAudioStream* _Nonnull stream, char* _Nonnull tags);
+int32_t AAudioStream_obtainTags(AAudioStream* _Nonnull stream,
+ char* _Nullable* _Nullable* _Nonnull tags);
+
+/**
+ * Free the memory containing the tags that is allocated when calling
+ * {@link #AAudioStream_obtainTags}.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @param tags reference provided by AAudioStream_obtainTags()
+ */
+void AAudioStream_releaseTags(AAudioStream* _Nonnull stream, char* _Nonnull * _Nullable tags);
#ifdef __cplusplus
}
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index cccb096..0758170 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -169,6 +169,7 @@
"libaudioclient_aidl_conversion",
"libaudiofoundation",
"libaudioutils",
+ "libbase",
"libbinder",
"libcutils",
"liblog",
diff --git a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
index 37c1a98..4e96219 100644
--- a/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
+++ b/media/libaaudio/src/binding/AAudioStreamConfiguration.cpp
@@ -59,7 +59,7 @@
setUsage(parcelable.usage);
static_assert(sizeof(aaudio_content_type_t) == sizeof(parcelable.contentType));
setContentType(parcelable.contentType);
- setTags(parcelable.tags);
+ setTags(std::set(parcelable.tags.begin(), parcelable.tags.end()));
static_assert(sizeof(aaudio_spatialization_behavior_t) ==
sizeof(parcelable.spatializationBehavior));
setSpatializationBehavior(parcelable.spatializationBehavior);
@@ -123,8 +123,8 @@
result.usage = getUsage();
static_assert(sizeof(aaudio_content_type_t) == sizeof(result.contentType));
result.contentType = getContentType();
- std::optional<std::string> tags = getTags();
- result.tags = tags.has_value() ? tags.value() : "";
+ auto tags = getTags();
+ result.tags = std::vector(tags.begin(), tags.end());
static_assert(
sizeof(aaudio_spatialization_behavior_t) == sizeof(result.spatializationBehavior));
result.spatializationBehavior = getSpatializationBehavior();
diff --git a/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
index 7d7abce..88ad449 100644
--- a/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
+++ b/media/libaaudio/src/binding/aidl/aaudio/StreamParameters.aidl
@@ -27,7 +27,7 @@
int /* aaudio_direction_t */ direction; // = AAUDIO_DIRECTION_OUTPUT;
int /* aaudio_usage_t */ usage; // = AAUDIO_UNSPECIFIED;
int /* aaudio_content_type_t */ contentType; // = AAUDIO_UNSPECIFIED;
- @utf8InCpp String tags; /* UTF8 */
+ @utf8InCpp String[] tags; /* UTF8 */
int /* aaudio_spatialization_behavior_t */spatializationBehavior; //= AAUDIO_UNSPECIFIED;
boolean isContentSpatialized; // = false;
int /* aaudio_input_preset_t */ inputPreset; // = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index de82471..64f115c 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -26,6 +26,7 @@
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
#include <system/aaudio/AAudio.h>
+#include <system/audio.h>
#include "AudioClock.h"
#include "AudioGlobal.h"
#include "AudioStreamBuilder.h"
@@ -182,15 +183,18 @@
streamBuilder->setContentType(contentType);
}
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_setTags(AAudioStreamBuilder* builder,
- const char* tags) {
- if (tags == nullptr || strlen(tags) >= AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE) {
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_addTag(AAudioStreamBuilder* builder,
+ const char* tags) {
+ if (tags == nullptr) {
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
- std::optional<std::string> optionalTags = std::string(tags);
- streamBuilder->setTags(optionalTags);
- return AAUDIO_OK;
+ return streamBuilder->addTag(tags);
+}
+
+AAUDIO_API void AAudioStreamBuilder_clearTags(AAudioStreamBuilder* builder) {
+ AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+ streamBuilder->clearTags();
}
AAUDIO_API void AAudioStreamBuilder_setSpatializationBehavior(AAudioStreamBuilder* builder,
@@ -598,20 +602,43 @@
return audioStream->getContentType();
}
-AAUDIO_API aaudio_result_t AAudioStream_getTags(AAudioStream* stream, char* tags)
+AAUDIO_API int32_t AAudioStream_obtainTags(AAudioStream* stream, char*** tags)
{
+ AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+ auto aaTags = audioStream->getTags();
+ if (aaTags.empty()) {
+ *tags = nullptr;
+ return 0;
+ }
+ *tags = new char*[aaTags.size()];
+ if (*tags == nullptr) {
+ return AAUDIO_ERROR_NO_MEMORY;
+ }
+ auto it = aaTags.begin();
+ for (int i = 0; it != aaTags.end(); i++, it++) {
+ (*tags)[i] = new char[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE];
+ if ((*tags)[i] == nullptr) {
+ for (int j = 0; j < i; ++j) {
+ delete[] (*tags)[i];
+ }
+ delete[] (*tags);
+ return AAUDIO_ERROR_NO_MEMORY;
+ }
+ strcpy((*tags)[i], it->c_str());
+ }
+ return aaTags.size();
+}
+
+AAUDIO_API void AAudioStream_releaseTags(AAudioStream* stream, char** tags) {
if (tags == nullptr) {
- return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
+ return;
}
AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
- std::optional<std::string> optTags = audioStream->getTags();
- if (optTags.has_value() && !optTags->empty()) {
- strncpy(tags, optTags.value().c_str(), AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
- tags[AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE-1] = '\0';
- } else {
- tags[0] = '\0';
+ const int tagsNum = audioStream->getTags().size();
+ for (int i = 0; i < tagsNum; ++i) {
+ delete[] tags[i];
}
- return AAUDIO_OK;
+ delete[] tags;
}
AAUDIO_API aaudio_spatialization_behavior_t AAudioStream_getSpatializationBehavior(
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index ed20d12..3090fb2 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "AAudioStreamParameters"
+
+#include <android-base/strings.h>
#include <utils/Log.h>
#include <system/audio.h>
#include <system/aaudio/AAudio.h>
@@ -212,7 +214,7 @@
// break;
}
- if (mTags.has_value() && mTags->size() >= AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE) {
+ if (getTagsAsString().size() >= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE) {
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
@@ -306,6 +308,10 @@
}
}
+std::string AAudioStreamParameters::getTagsAsString() const {
+ return android::base::Join(mTags, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
+}
+
void AAudioStreamParameters::dump() const {
ALOGD("mDeviceIds = %s", android::toString(mDeviceIds).c_str());
ALOGD("mSessionId = %6d", mSessionId);
@@ -318,7 +324,7 @@
ALOGD("mBufferCapacity = %6d", mBufferCapacity);
ALOGD("mUsage = %6d", mUsage);
ALOGD("mContentType = %6d", mContentType);
- ALOGD("mTags = %s", mTags.has_value() ? mTags.value().c_str() : "");
+ ALOGD("mTags = %s", getTagsAsString().c_str());
ALOGD("mSpatializationBehavior = %6d", mSpatializationBehavior);
ALOGD("mIsContentSpatialized = %s", mIsContentSpatialized ? "true" : "false");
ALOGD("mInputPreset = %6d", mInputPreset);
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.h b/media/libaaudio/src/core/AAudioStreamParameters.h
index c4c0a4f..94c5e89 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.h
+++ b/media/libaaudio/src/core/AAudioStreamParameters.h
@@ -98,14 +98,16 @@
mContentType = contentType;
}
- void setTags(const std::optional<std::string>& tags) {
+ void setTags(const std::set<std::string>& tags) {
mTags = tags;
}
- const std::optional<std::string> getTags() const {
+ const std::set<std::string>& getTags() const {
return mTags;
}
+ std::string getTagsAsString() const;
+
aaudio_spatialization_behavior_t getSpatializationBehavior() const {
return mSpatializationBehavior;
}
@@ -221,6 +223,9 @@
void dump() const;
+protected:
+ std::set<std::string> mTags;
+
private:
aaudio_result_t validateChannelMask() const;
@@ -232,7 +237,6 @@
aaudio_direction_t mDirection = AAUDIO_DIRECTION_OUTPUT;
aaudio_usage_t mUsage = AAUDIO_UNSPECIFIED;
aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED;
- std::optional<std::string> mTags = {};
aaudio_spatialization_behavior_t mSpatializationBehavior
= AAUDIO_UNSPECIFIED;
bool mIsContentSpatialized = false;
diff --git a/media/libaaudio/src/core/AudioGlobal.h b/media/libaaudio/src/core/AudioGlobal.h
index 7ff344b..c4ef87d 100644
--- a/media/libaaudio/src/core/AudioGlobal.h
+++ b/media/libaaudio/src/core/AudioGlobal.h
@@ -30,6 +30,8 @@
};
+static const char AUDIO_ATTRIBUTES_TAGS_SEPARATOR = ';';
+
aaudio_policy_t AudioGlobal_getMMapPolicy();
aaudio_result_t AudioGlobal_setMMapPolicy(aaudio_policy_t policy);
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index 468bcfa..fdda3b7 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -26,6 +26,7 @@
#include <sys/syscall.h>
#include <aaudio/AAudio.h>
+#include <android-base/strings.h>
#include "AudioStreamBuilder.h"
#include "AudioStream.h"
@@ -659,6 +660,10 @@
return getState();
}
+std::string AudioStream::getTagsAsString() const {
+ return android::base::Join(mTags, AUDIO_ATTRIBUTES_TAGS_SEPARATOR);
+}
+
void AudioStream::MyPlayerBase::registerWithAudioManager(const android::sp<AudioStream>& parent) {
std::lock_guard<std::mutex> lock(mParentLock);
mParent = parent;
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index 0ddc8ed..38ed5be 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -19,6 +19,7 @@
#include <atomic>
#include <mutex>
+#include <set>
#include <stdint.h>
#include <android-base/thread_annotations.h>
@@ -291,7 +292,7 @@
return mContentType;
}
- const std::optional<std::string> getTags() const {
+ const std::set<std::string>& getTags() const {
return mTags;
}
@@ -715,10 +716,12 @@
/**
* This should not be called after the open() call.
*/
- void setTags(const std::optional<std::string> &tags) {
+ void setTags(const std::set<std::string> &tags) {
mTags = tags;
}
+ std::string getTagsAsString() const;
+
void setSpatializationBehavior(aaudio_spatialization_behavior_t spatializationBehavior) {
mSpatializationBehavior = spatializationBehavior;
}
@@ -808,7 +811,7 @@
aaudio_usage_t mUsage = AAUDIO_UNSPECIFIED;
aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED;
- std::optional<std::string> mTags = {};
+ std::set<std::string> mTags;
aaudio_spatialization_behavior_t mSpatializationBehavior = AAUDIO_UNSPECIFIED;
bool mIsContentSpatialized = false;
aaudio_input_preset_t mInputPreset = AAUDIO_UNSPECIFIED;
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index 61881cb..a88052d 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include <new>
+#include <numeric>
#include <stdint.h>
#include <vector>
@@ -28,6 +29,7 @@
#include <android/media/audio/common/AudioMMapPolicyInfo.h>
#include <android/media/audio/common/AudioMMapPolicyType.h>
#include <media/AudioSystem.h>
+#include <system/aaudio/AAudio.h>
#include "binding/AAudioBinderClient.h"
#include "client/AudioStreamInternalCapture.h"
@@ -292,6 +294,24 @@
return AAUDIO_OK;
}
+aaudio_result_t AudioStreamBuilder::addTag(const char* tag) {
+ const std::string tagStr(tag);
+ mTags.insert(tagStr);
+ // The tags will be joined with `;` and ended with null terminator when sending to the HAL.
+ const int tagsLength = std::accumulate(
+ mTags.begin(), mTags.end(), 0, [](int v, const std::string& s) { return v + s.size(); })
+ + mTags.size();
+ if (tagsLength <= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE) {
+ return AAUDIO_OK;
+ }
+ mTags.erase(tagStr);
+ return AAUDIO_ERROR_OUT_OF_RANGE;
+}
+
+void AudioStreamBuilder::clearTags() {
+ mTags.clear();
+}
+
static const char *AAudio_convertSharingModeToShortText(aaudio_sharing_mode_t sharingMode) {
switch (sharingMode) {
case AAUDIO_SHARING_MODE_EXCLUSIVE:
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.h b/media/libaaudio/src/core/AudioStreamBuilder.h
index d0678ae..4f66f5b 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.h
+++ b/media/libaaudio/src/core/AudioStreamBuilder.h
@@ -17,6 +17,7 @@
#ifndef AAUDIO_AUDIO_STREAM_BUILDER_H
#define AAUDIO_AUDIO_STREAM_BUILDER_H
+#include <set>
#include <stdint.h>
#include <aaudio/AAudio.h>
@@ -122,6 +123,10 @@
return this;
}
+ aaudio_result_t addTag(const char* tag);
+
+ void clearTags();
+
aaudio_result_t build(AudioStream **streamPtr);
virtual aaudio_result_t validate() const override;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index da15563..f0a25b5 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -24,6 +24,7 @@
#include <aaudio/AAudio.h>
#include <com_android_media_aaudio.h>
#include <system/audio.h>
+#include <system/aaudio/AAudio.h>
#include "core/AudioGlobal.h"
#include "legacy/AudioStreamLegacy.h"
@@ -149,13 +150,14 @@
builder.isContentSpatialized(),
flags);
- const std::optional<std::string> tags = builder.getTags();
+ const std::string tags = getTagsAsString();
audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
attributes.content_type = contentType;
attributes.usage = usage;
attributes.flags = attributesFlags;
- if (tags.has_value() && !tags.value().empty()) {
- strcpy(attributes.tags, tags.value().c_str());
+ if (!tags.empty()) {
+ strncpy(attributes.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
+ attributes.tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1] = '\0';
}
audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
diff --git a/media/libaaudio/src/libaaudio.map.txt b/media/libaaudio/src/libaaudio.map.txt
index 44bb4c6..2425ae4 100644
--- a/media/libaaudio/src/libaaudio.map.txt
+++ b/media/libaaudio/src/libaaudio.map.txt
@@ -79,8 +79,10 @@
AAudioStream_getOffloadPadding; #introduced=36
AAudioStream_setOffloadEndOfStream; #introduced=36
- AAudioStreamBuilder_setTags; # systemapi
- AAudioStream_getTags; # systemapi
+ AAudioStreamBuilder_addTag; # systemapi
+ AAudioStreamBuilder_clearTags; # systemapi
+ AAudioStream_obtainTags; # systemapi
+ AAudioStream_releaseTags; #systemapi
local:
*;
};
diff --git a/media/libaaudio/tests/test_attributes.cpp b/media/libaaudio/tests/test_attributes.cpp
index 045c236..fcb083d 100644
--- a/media/libaaudio/tests/test_attributes.cpp
+++ b/media/libaaudio/tests/test_attributes.cpp
@@ -14,15 +14,19 @@
* limitations under the License.
*/
-// Test AAudio attributes such as Usage, ContentType and InputPreset.
+// Test AAudio attributes such as Usage, ContentType, InputPreset and Tags.
// TODO Many of these tests are duplicates of CTS tests in
// "test_aaudio_attributes.cpp". That other file is more current.
// So these tests could be deleted.
+// Also note audio attributes tags, which is system api, it cannot be tested
+// from the CTS. In that case, please do not delete audio attributes tags test.
+#include <algorithm>
#include <memory>
#include <stdio.h>
#include <unistd.h>
+#include <vector>
#include <aaudio/AAudio.h>
#include <gtest/gtest.h>
@@ -38,17 +42,18 @@
static void checkAttributes(aaudio_performance_mode_t perfMode,
aaudio_usage_t usage,
aaudio_content_type_t contentType,
- const char * tags = nullptr,
+ std::vector<const char*>* tags = nullptr,
aaudio_input_preset_t preset = DONT_SET,
aaudio_allowed_capture_policy_t capturePolicy = DONT_SET,
int privacyMode = DONT_SET,
- aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT) {
+ aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT,
+ const char* tagToBeCleared = "TagsToBeCleared") {
std::unique_ptr<float[]> buffer(new float[kNumFrames * kChannelCount]);
AAudioStreamBuilder *aaudioBuilder = nullptr;
AAudioStream *aaudioStream = nullptr;
- aaudio_result_t expectedSetTagsResult = AAUDIO_OK;
+ aaudio_result_t expectedAddTagResult = AAUDIO_OK;
// Use an AAudioStreamBuilder to contain requested parameters.
ASSERT_EQ(AAUDIO_OK, AAudio_createStreamBuilder(&aaudioBuilder));
@@ -64,11 +69,32 @@
if (contentType != DONT_SET) {
AAudioStreamBuilder_setContentType(aaudioBuilder, contentType);
}
+ std::set<std::string> addedTags;
if (tags != nullptr) {
- aaudio_result_t result = AAudioStreamBuilder_setTags(aaudioBuilder, tags);
- expectedSetTagsResult = (strlen(tags) >= AUDIO_ATTRIBUTES_TAGS_MAX_SIZE) ?
- AAUDIO_ERROR_ILLEGAL_ARGUMENT : AAUDIO_OK;
- EXPECT_EQ(result, expectedSetTagsResult);
+ EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_addTag(aaudioBuilder, tagToBeCleared));
+ AAudioStreamBuilder_clearTags(aaudioBuilder);
+ int totalLength = 0;
+ for (int i = 0; i < tags->size(); ++i) {
+ if (tags->at(i) == nullptr) {
+ EXPECT_EQ(AAUDIO_ERROR_ILLEGAL_ARGUMENT,
+ AAudioStreamBuilder_addTag(aaudioBuilder, tags->at(i)));
+ continue;
+ }
+ // When sending all tags across the framework and the HAL, all tags are joined as a
+ // string. In that case, a delimiter will be added if the tag is not the last added
+ // tag or NULL terminator will be added if the tag is the last added tag.
+ int lengthToAdd = strlen(tags->at(i)) + 1;
+ totalLength += lengthToAdd;
+ aaudio_result_t result = AAudioStreamBuilder_addTag(aaudioBuilder, tags->at(i));
+ expectedAddTagResult = (totalLength > AUDIO_ATTRIBUTES_TAGS_MAX_SIZE) ?
+ AAUDIO_ERROR_OUT_OF_RANGE : AAUDIO_OK;
+ EXPECT_EQ(result, expectedAddTagResult) << "total length=" << totalLength;
+ if (expectedAddTagResult != AAUDIO_OK) {
+ totalLength -= lengthToAdd;
+ } else {
+ addedTags.insert(tags->at(i));
+ }
+ }
}
if (preset != DONT_SET) {
AAudioStreamBuilder_setInputPreset(aaudioBuilder, preset);
@@ -97,19 +123,16 @@
: contentType;
EXPECT_EQ(expectedContentType, AAudioStream_getContentType(aaudioStream));
- char readTags[AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE] = {};
- EXPECT_EQ(AAUDIO_OK, AAudioStream_getTags(aaudioStream, readTags))
- << "Expected tags=" << (tags != nullptr ? tags : "null") << ", got tags=" << readTags;;
- EXPECT_LT(strlen(readTags), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE)
- << "expected tags len " << strlen(readTags) << " less than "
- << AUDIO_ATTRIBUTES_TAGS_MAX_SIZE;
-
- // Null tags or failed to set, empty tags expected (default initializer)
- const char * expectedTags = tags == nullptr ?
- "" : (expectedSetTagsResult != AAUDIO_OK ? "" : tags);
- // Oversized tags will be discarded
- EXPECT_TRUE(std::strcmp(expectedTags, readTags) == 0)
- << "Expected tags=" << expectedTags << ", got tags=" << readTags;
+ char** readTags = nullptr;
+ const int32_t numOfTagsRead = AAudioStream_obtainTags(aaudioStream, &readTags);
+ EXPECT_EQ(addedTags.size(), numOfTagsRead);
+ EXPECT_EQ(numOfTagsRead == 0, readTags == nullptr);
+ std::set<std::string> readTagsSet;
+ for (int i = 0; i < numOfTagsRead; ++i) {
+ readTagsSet.insert(readTags[i]);
+ }
+ EXPECT_EQ(addedTags, readTagsSet);
+ AAudioStream_releaseTags(aaudioStream, readTags);
aaudio_input_preset_t expectedPreset =
(preset == DONT_SET || preset == AAUDIO_UNSPECIFIED)
@@ -167,7 +190,8 @@
static const std::string oversizedTags = std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE, 'B');
static const std::string maxSizeTags = std::string(AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1, 'C');
-static const char * const sTags[] = {
+static const int TOTAL_TAGS = 7;
+static const char * const sTags[TOTAL_TAGS] = {
nullptr,
"",
"oem=routing_extension",
@@ -225,8 +249,13 @@
}
static void checkAttributesTags(aaudio_performance_mode_t perfMode) {
- for (const char * const tags : sTags) {
- checkAttributes(perfMode, DONT_SET, DONT_SET, tags);
+ checkAttributes(perfMode, DONT_SET, DONT_SET, nullptr /*tags*/);
+ for (int i = 0; i < TOTAL_TAGS; ++i) {
+ std::vector<const char*> tags = {sTags[i]};
+ if (i > 0) {
+ tags.push_back(sTags[i-1]);
+ }
+ checkAttributes(perfMode, DONT_SET, DONT_SET, &tags);
}
}
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index e3b79b2..359f3c1 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -310,8 +310,16 @@
ts = NULL;
break;
}
+
int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex);
- if (!(old & CBLK_FUTEX_WAKE)) {
+
+ // Check inactive to prevent waiting if the track has been disabled due to underrun
+ // (or invalidated). The subsequent call to obtainBufer will return NOT_ENOUGH_DATA
+ // (or DEAD_OBJECT) and restart (or restore) the track.
+ const int32_t current_flags = android_atomic_acquire_load(&cblk->mFlags);
+ const bool inactive = current_flags & (CBLK_INVALID | CBLK_DISABLED);
+
+ if (!(old & CBLK_FUTEX_WAKE) && !inactive) {
if (measure && !beforeIsValid) {
clock_gettime(CLOCK_MONOTONIC, &before);
beforeIsValid = true;
diff --git a/media/libaudioclient/aidl/android/media/ISpatializer.aidl b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
index 37dd776..4a5321e 100644
--- a/media/libaudioclient/aidl/android/media/ISpatializer.aidl
+++ b/media/libaudioclient/aidl/android/media/ISpatializer.aidl
@@ -163,4 +163,11 @@
* Gets the io handle of the output stream the spatializer is connected to.
*/
int getOutput();
+
+ /**
+ * Returns a list of channel masks that represent the widest channel masks the spatializer
+ * is capable of rendering with individual channel positions.
+ * Note that each channel mask is in the native format.
+ */
+ int[] getSpatializedChannelMasks();
}
diff --git a/media/libaudiopermission/Android.bp b/media/libaudiopermission/Android.bp
index 7275fd7..161e5a7 100644
--- a/media/libaudiopermission/Android.bp
+++ b/media/libaudiopermission/Android.bp
@@ -83,7 +83,7 @@
}
cc_test {
- name: "libaudiopermission_test",
+ name: "libaudiopermission_tests",
host_supported: true,
defaults: [
"libmediautils_tests_config",
@@ -100,10 +100,7 @@
"liblog",
"libutils",
],
- srcs: [
- "tests/NativePermissionControllerTest.cpp",
- "tests/ValidatedAttributionSourceStateTest.cpp",
- ],
+ srcs: ["tests/*.cpp"],
test_options: {
unit_test: true,
},
diff --git a/media/libaudiopermission/include/media/AttrSourceIter.h b/media/libaudiopermission/include/media/AttrSourceIter.h
new file mode 100644
index 0000000..609d218
--- /dev/null
+++ b/media/libaudiopermission/include/media/AttrSourceIter.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android/content/AttributionSourceState.h>
+
+#include <iterator>
+
+// AttributionSourceState are essentially an intrusive linked list, where the next field carries
+// the pointer to the next element. These iterator helpers allow for convenient iteration over the
+// entire attribution chain. Usage:
+// std::for_each(AttrSourceIter::begin(mAttributionSourceState), AttrSourceIter::end(), ...)
+namespace android::media::permission::AttrSourceIter {
+
+class ConstIter {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+ using value_type = ::android::content::AttributionSourceState;
+ using pointer = const value_type*;
+ using reference = const value_type&;
+
+ ConstIter(const ::android::content::AttributionSourceState* attr) : mAttr(attr) {}
+
+ reference operator*() const { return *mAttr; }
+ pointer operator->() const { return mAttr; }
+
+ ConstIter& operator++() {
+ mAttr = !mAttr->next.empty() ? mAttr->next.data() : nullptr;
+ return *this;
+ }
+ ConstIter operator++(int) {
+ ConstIter tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(const ConstIter& a, const ConstIter& b) = default;
+
+ static ConstIter end() { return ConstIter(nullptr); }
+
+ private:
+ const ::android::content::AttributionSourceState* mAttr;
+};
+
+/**
+ * Non-const iterator. Note, AttributionSourceState is conceptually a linked list on the next field.
+ * Be very careful if `next` is modified over iteration, as it can go wrong easily.
+ */
+class Iter {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+ using value_type = ::android::content::AttributionSourceState;
+ using pointer = value_type*;
+ using reference = value_type&;
+
+ Iter(::android::content::AttributionSourceState* attr) : mAttr(attr) {}
+
+ reference operator*() const { return *mAttr; }
+ pointer operator->() const { return mAttr; }
+
+ Iter& operator++() {
+ mAttr = !mAttr->next.empty() ? mAttr->next.data() : nullptr;
+ return *this;
+ }
+ Iter operator++(int) {
+ Iter tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ friend bool operator==(const Iter& a, const Iter& b) = default;
+
+ operator ConstIter() const { return ConstIter(mAttr); }
+
+ static Iter end() { return Iter(nullptr); }
+
+ private:
+ ::android::content::AttributionSourceState* mAttr;
+};
+
+inline Iter begin(::android::content::AttributionSourceState& a) {
+ return Iter(&a);
+}
+inline Iter end() {
+ return Iter::end();
+}
+inline ConstIter cbegin(const ::android::content::AttributionSourceState& a) {
+ return ConstIter(&a);
+}
+inline ConstIter cend() {
+ return ConstIter::end();
+}
+} // namespace com::android::media::permission::AttrSourceIter
diff --git a/media/libaudiopermission/tests/AttrSourceIterTests.cpp b/media/libaudiopermission/tests/AttrSourceIterTests.cpp
new file mode 100644
index 0000000..57d326d
--- /dev/null
+++ b/media/libaudiopermission/tests/AttrSourceIterTests.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/content/AttributionSourceState.h>
+#include <media/AttrSourceIter.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+
+using ::android::content::AttributionSourceState;
+using ::android::media::permission::AttrSourceIter::begin;
+using ::android::media::permission::AttrSourceIter::cbegin;
+using ::android::media::permission::AttrSourceIter::cend;
+using ::android::media::permission::AttrSourceIter::end;
+
+using ::android::media::permission::AttrSourceIter::ConstIter;
+
+using ::testing::ContainerEq;
+using ::testing::ElementsAreArray;
+using ::testing::Eq;
+using ::testing::Return;
+
+class AttrSourceIterTest : public ::testing::Test {
+ public:
+ AttrSourceIterTest() {
+ mAttr.pid = 1;
+ mAttr.uid = 1;
+ AttributionSourceState next;
+ next.pid = 2;
+ next.uid = 2;
+ AttributionSourceState nextnext;
+ nextnext.pid = 3;
+ nextnext.uid = 3;
+ next.next = {nextnext};
+ mAttr.next = {next};
+ }
+
+ protected:
+ AttributionSourceState mAttr;
+};
+
+TEST_F(AttrSourceIterTest, constIter) {
+ const AttributionSourceState& ref = mAttr;
+ std::vector<int> mPids;
+ std::transform(cbegin(ref), cend(), std::back_inserter(mPids),
+ [](const auto& x) { return x.pid; });
+ EXPECT_THAT(mPids, ElementsAreArray({1, 2, 3}));
+}
+
+TEST_F(AttrSourceIterTest, nonConstIter) {
+ AttributionSourceState expected;
+ {
+ expected.pid = 2;
+ expected.uid = 1;
+ AttributionSourceState expectedNext;
+ expectedNext.pid = 4;
+ expectedNext.uid = 2;
+ AttributionSourceState expectedNextNext;
+ expectedNextNext.pid = 6;
+ expectedNextNext.uid = 3;
+ expectedNext.next = {expectedNextNext};
+ expected.next = {expectedNext};
+ }
+ std::for_each(begin(mAttr), end(), [](auto& x) { x.pid = x.pid * 2; });
+
+ EXPECT_THAT(mAttr, Eq(expected));
+}
+
+TEST_F(AttrSourceIterTest, nonConstIterReferenceEquals) {
+ const AttributionSourceState& ref = mAttr;
+ std::vector<const AttributionSourceState*> attrs;
+ std::transform(cbegin(ref), cend(), std::back_inserter(attrs),
+ [](const auto& x) { return &x; });
+ std::for_each(begin(mAttr), end(), [](auto& x) { x.pid = x.pid * 2; });
+ std::vector<const AttributionSourceState*> attrsAfter;
+ std::transform(cbegin(ref), cend(), std::back_inserter(attrsAfter),
+ [](const auto& x) { return &x; });
+ EXPECT_THAT(attrs, ContainerEq(attrsAfter));
+}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 303f313..c635feb 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -3013,6 +3013,18 @@
}
device = inputDesc->getDevice();
ALOGV("%s reusing MMAP input %d for session %d", __FUNCTION__, requestedInput, session);
+ auto permRes = mpClientInterface->checkPermissionForInput(attributionSource, permReq);
+ if (!permRes.has_value()) return base::unexpected {permRes.error()};
+ if (!permRes.value()) {
+ return base::unexpected{Status::fromExceptionCode(
+ EX_SECURITY, String8::format("%s: %s missing perms for source %d mix %d vdi %d"
+ "hotword? %d callredir? %d", __func__, attributionSource.toString().c_str(),
+ static_cast<int>(permReq.source),
+ static_cast<int>(permReq.mixType),
+ permReq.virtualDeviceId,
+ permReq.isHotword,
+ permReq.isCallRedir))};
+ }
} else {
if (attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX &&
extractAddressFromAudioAttributes(attributes).has_value()) {
diff --git a/services/audiopolicy/service/AudioRecordClient.cpp b/services/audiopolicy/service/AudioRecordClient.cpp
index 01e557c..79a7458 100644
--- a/services/audiopolicy/service/AudioRecordClient.cpp
+++ b/services/audiopolicy/service/AudioRecordClient.cpp
@@ -21,6 +21,7 @@
#include "binder/AppOpsManager.h"
#include "mediautils/ServiceUtilities.h"
#include <android_media_audiopolicy.h>
+#include <media/AttrSourceIter.h>
#include <algorithm>
@@ -58,39 +59,6 @@
bool doesPackageTargetAtLeastU(std::string_view packageName) {
return getTargetSdkForPackageName(packageName) >= __ANDROID_API_U__;
}
-
-class AttrSourceItr {
- public:
- using iterator_category = std::forward_iterator_tag;
- using difference_type = std::ptrdiff_t;
- using value_type = AttributionSourceState;
- using pointer = value_type*;
- using reference = value_type&;
-
- AttrSourceItr() : mAttr(nullptr) {}
-
- AttrSourceItr(AttributionSourceState& attr) : mAttr(&attr) {}
-
- reference operator*() const { return *mAttr; }
- pointer operator->() const { return mAttr; }
-
- AttrSourceItr& operator++() {
- mAttr = !mAttr->next.empty() ? mAttr->next.data() : nullptr;
- return *this;
- }
-
- AttrSourceItr operator++(int) {
- AttrSourceItr tmp = *this;
- ++(*this);
- return tmp;
- }
-
- friend bool operator==(const AttrSourceItr& a, const AttrSourceItr& b) = default;
-
- static AttrSourceItr end() { return AttrSourceItr{}; }
-private:
- AttributionSourceState * mAttr;
-};
} // anonymous
// static
@@ -124,27 +92,32 @@
commandThread);
}
+// The vdi is carried in the attribution source for appops perm checks.
+// Overwrite the entire chain with the vdi associated with the mix this client is attached to
+// This ensures the checkOps triggered by the listener are correct.
+// Note: we still only register for events by package name, so we assume that we get events
+// independent of vdi.
+static AttributionSourceState& overwriteVdi(AttributionSourceState& chain, int vdi) {
+ using permission::AttrSourceIter::begin;
+ using permission::AttrSourceIter::end;
+ if (vdi != 0 /* default vdi */) {
+ std::for_each(begin(chain), end(), [vdi](auto& attr) { attr.deviceId = vdi; });
+ }
+ return chain;
+}
+
OpRecordAudioMonitor::OpRecordAudioMonitor(
- const AttributionSourceState &attributionSource,
+ AttributionSourceState attributionSource,
const uint32_t virtualDeviceId, const audio_attributes_t &attr,
int32_t appOp,
bool shouldMonitorRecord,
wp<AudioPolicyService::AudioCommandThread> commandThread) :
- mHasOp(true), mAttributionSource(attributionSource),
- mVirtualDeviceId(virtualDeviceId), mAttr(attr), mAppOp(appOp),
+ mHasOp(true),
+ mAttributionSource(overwriteVdi(attributionSource, virtualDeviceId)),
+ mVirtualDeviceId(virtualDeviceId), mAttr(attr),
+ mAppOp(appOp),
mShouldMonitorRecord(shouldMonitorRecord),
- mCommandThread(commandThread) {
- // The vdi is carried in the attribution source for appops perm checks.
- // Overwrite the entire chain with the vdi associated with the mix this client is attached to
- // This ensures the checkOps triggered by the listener are correct.
- // Note: we still only register for events by package name, so we assume that we get events
- // independent of vdi.
- if (mVirtualDeviceId != 0 /* default vdi */) {
- // TODO (atneya@) lift for const
- std::for_each(AttrSourceItr{mAttributionSource}, AttrSourceItr::end(),
- [&](auto& attr) { attr.deviceId = mVirtualDeviceId; });
- }
-}
+ mCommandThread(commandThread) {}
OpRecordAudioMonitor::~OpRecordAudioMonitor()
{
@@ -156,6 +129,9 @@
void OpRecordAudioMonitor::onFirstRef()
{
+ using permission::AttrSourceIter::cbegin;
+ using permission::AttrSourceIter::cend;
+
checkOp();
mOpCallback = new RecordAudioOpCallback(this);
ALOGV("start watching op %d for %s", mAppOp, mAttributionSource.toString().c_str());
@@ -165,7 +141,7 @@
: 0;
const auto reg = [&](int32_t op) {
- std::for_each(AttrSourceItr{mAttributionSource}, AttrSourceItr::end(),
+ std::for_each(cbegin(mAttributionSource), cend(),
[&](const auto& attr) {
mAppOpsManager.startWatchingMode(
op,
@@ -191,9 +167,11 @@
// - not called from constructor,
// - not called from RecordAudioOpCallback because the callback is not installed in this case
void OpRecordAudioMonitor::checkOp(bool updateUidStates) {
+ using permission::AttrSourceIter::cbegin;
+ using permission::AttrSourceIter::cend;
+
const auto check = [&](int32_t op) -> bool {
- return std::all_of(
- AttrSourceItr{mAttributionSource}, AttrSourceItr::end(), [&](const auto& x) {
+ return std::all_of(cbegin(mAttributionSource), cend(), [&](const auto& x) {
return mAppOpsManager.checkOp(op, x.uid,
VALUE_OR_FATAL(aidl2legacy_string_view_String16(
x.packageName.value_or("")))) ==
diff --git a/services/audiopolicy/service/AudioRecordClient.h b/services/audiopolicy/service/AudioRecordClient.h
index 3553f1d..6037a8d 100644
--- a/services/audiopolicy/service/AudioRecordClient.h
+++ b/services/audiopolicy/service/AudioRecordClient.h
@@ -43,7 +43,7 @@
wp<AudioPolicyService::AudioCommandThread> commandThread);
private:
- OpRecordAudioMonitor(const AttributionSourceState &attributionSource,
+ OpRecordAudioMonitor(AttributionSourceState attributionSource,
uint32_t virtualDeviceId,
const audio_attributes_t &attr,
int32_t appOp,
@@ -71,7 +71,7 @@
void checkOp(bool updateUidStates = false);
std::atomic_bool mHasOp;
- AttributionSourceState mAttributionSource;
+ const AttributionSourceState mAttributionSource;
const uint32_t mVirtualDeviceId;
const audio_attributes_t mAttr;
const int32_t mAppOp;
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index c7740ad..d177b92 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -413,6 +413,29 @@
return BAD_VALUE;
}
+ std::vector<audio_channel_mask_t> spatializedChannelMasks;
+ status = getHalParameter<true>(effect, SPATIALIZER_PARAM_SPATIALIZED_CHANNEL_MASKS,
+ &spatializedChannelMasks);
+ if (status != NO_ERROR) {
+ ALOGW("%s: cannot get SPATIALIZER_PARAM_SPATIALIZED_CHANNEL_MASKS", __func__);
+ return status;
+ }
+ if (spatializedChannelMasks.empty()) {
+ ALOGW("%s: SPATIALIZER_PARAM_SPATIALIZED_CHANNEL_MASKS reports empty", __func__);
+ return BAD_VALUE;
+ }
+ for (const audio_channel_mask_t spatializedMask : spatializedChannelMasks) {
+ // spatialized masks must be contained in the supported input masks
+ if (std::find(mChannelMasks.begin(), mChannelMasks.end(), spatializedMask)
+ != mChannelMasks.end()) {
+ mSpatializedChannelMasks.emplace_back(spatializedMask);
+ } else {
+ ALOGE("%s: spatialized mask %#x not in list reported by PARAM_SUPPORTED_CHANNEL_MASKS",
+ __func__, spatializedMask);
+ return BAD_VALUE;
+ }
+ }
+
if (com::android::media::audio::dsa_over_bt_le_audio()
&& mSupportsHeadTracking) {
mHeadtrackingConnectionMode = HeadTracking::ConnectionMode::FRAMEWORK_PROCESSED;
@@ -474,6 +497,17 @@
return config;
}
+Status Spatializer::getSpatializedChannelMasks(std::vector<int>* masks) {
+ audio_utils::lock_guard lock(mMutex);
+ ALOGV("%s", __func__);
+ if (masks == nullptr) {
+ return binderStatusFromStatusT(BAD_VALUE);
+ }
+ masks->insert(masks->end(), mSpatializedChannelMasks.begin(),
+ mSpatializedChannelMasks.end());
+ return Status::ok();
+ }
+
status_t Spatializer::registerCallback(
const sp<media::INativeSpatializerCallback>& callback) {
audio_utils::lock_guard lock(mMutex);
@@ -1254,6 +1288,10 @@
for (auto& mask : mChannelMasks) {
base::StringAppendF(&ss, "%s", audio_channel_out_mask_to_string(mask));
}
+ base::StringAppendF(&ss, "%smSpatializedChannelMasks: ", prefixSpace.c_str());
+ for (auto& mask : mSpatializedChannelMasks) {
+ base::StringAppendF(&ss, "%s", audio_channel_out_mask_to_string(mask));
+ }
base::StringAppendF(&ss, "\n%smSupportsHeadTracking: %s\n", prefixSpace.c_str(),
mSupportsHeadTracking ? "true" : "false");
// 2. Settings (Output, tracks)
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index 5ea3258..6141165 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -133,6 +133,7 @@
binder::Status setParameter(int key, const std::vector<unsigned char>& value) override;
binder::Status getParameter(int key, std::vector<unsigned char> *value) override;
binder::Status getOutput(int *output);
+ binder::Status getSpatializedChannelMasks(std::vector<int>* masks) override;
/** IBinder::DeathRecipient. Listen to the death of the INativeSpatializerCallback. */
virtual void binderDied(const wp<IBinder>& who);
@@ -536,6 +537,7 @@
std::vector<media::audio::common::HeadTracking::Mode> mHeadTrackingModes;
std::vector<media::audio::common::Spatialization::Mode> mSpatializationModes;
std::vector<audio_channel_mask_t> mChannelMasks;
+ std::vector<audio_channel_mask_t> mSpatializedChannelMasks;
bool mSupportsHeadTracking;
/** List of supported head tracking connection modes reported by the spatializer.
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index c050f1b..d95242b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -3882,12 +3882,6 @@
it != captureRequest->mSettingsList.end(); it++) {
if (parent->mUHRCropAndMeteringRegionMappers.find(it->cameraId) ==
parent->mUHRCropAndMeteringRegionMappers.end()) {
- if (removeFwkOnlyKeys(&(it->metadata)) != OK) {
- SET_ERR("RequestThread: Unable to remove fwk-only keys from request"
- "%d: %s (%d)", halRequest->frame_number, strerror(-res),
- res);
- return INVALID_OPERATION;
- }
continue;
}
@@ -3902,12 +3896,6 @@
return INVALID_OPERATION;
}
captureRequest->mUHRCropAndMeteringRegionsUpdated = true;
- if (removeFwkOnlyKeys(&(it->metadata)) != OK) {
- SET_ERR("RequestThread: Unable to remove fwk-only keys from request"
- "%d: %s (%d)", halRequest->frame_number, strerror(-res),
- res);
- return INVALID_OPERATION;
- }
}
}
@@ -3981,7 +3969,13 @@
"%d: %s (%d)", halRequest->frame_number, strerror(-res), res);
return INVALID_OPERATION;
}
-
+ res = removeFwkOnlyKeys(&(it->metadata));
+ if (res != OK) {
+ SET_ERR("RequestThread: Unable to remove fwk-only keys from request"
+ "%d: %s (%d)", halRequest->frame_number, strerror(-res),
+ res);
+ return INVALID_OPERATION;
+ }
if (!parent->mSupportsExtensionKeys) {
res = filterExtensionKeys(&it->metadata);
if (res != OK) {
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 66dcbc3..7a53847 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -458,11 +458,11 @@
}
// Note: Physical camera continues to use SCALER_CROP_REGION to reflect
- // zoom levels.
+ // zoom levels. Model this by treating app-set ZOOM_RATIO as 1x.
res = states.zoomRatioMappers[cameraId].updateCaptureResult(
&physicalMetadata.mCameraMetadataInfo.get<CameraMetadataInfo::metadata>(),
/*zoomMethodIsRatio*/false,
- /*zoomRatioIs1*/false);
+ /*zoomRatioIs1*/true);
if (res != OK) {
SET_ERR("Failed to update camera %s's physical zoom ratio metadata for "
"frame %d: %s(%d)", cameraId.c_str(), frameNumber, strerror(-res), res);
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
index 80af140..85a5afc 100644
--- a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
@@ -58,6 +58,10 @@
return ret.str();
}
+static std::string getAppOpsMessage(const std::string& cameraId) {
+ return cameraId.empty() ? std::string() : std::string("start camera ") + cameraId;
+}
+
} // namespace
namespace android {
@@ -298,33 +302,37 @@
bool AttributionAndPermissionUtils::hasPermissionsForCamera(
const std::string& cameraId, const AttributionSourceState& attributionSource,
bool forDataDelivery, bool checkAutomotive) {
- return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE, forDataDelivery, /* startDataDelivery */ false,
- checkAutomotive) != PermissionChecker::PERMISSION_HARD_DENIED;
+ return checkPermission(cameraId, sCameraPermission, attributionSource,
+ getAppOpsMessage(cameraId), AppOpsManager::OP_NONE, forDataDelivery,
+ /* startDataDelivery */ false, checkAutomotive)
+ != PermissionChecker::PERMISSION_HARD_DENIED;
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionsForCameraForPreflight(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
- return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE, /* forDataDelivery */ false,
- /* startDataDelivery */ false, /* checkAutomotive */ false);
+ return checkPermission(cameraId, sCameraPermission, attributionSource,
+ getAppOpsMessage(cameraId), AppOpsManager::OP_NONE,
+ /* forDataDelivery */ false, /* startDataDelivery */ false,
+ /* checkAutomotive */ false);
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionsForCameraForDataDelivery(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
- return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE, /* forDataDelivery */ true,
- /* startDataDelivery */ false, /* checkAutomotive */ false);
+ return checkPermission(cameraId, sCameraPermission, attributionSource,
+ getAppOpsMessage(cameraId), AppOpsManager::OP_NONE,
+ /* forDataDelivery */ true, /* startDataDelivery */ false,
+ /* checkAutomotive */ false);
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionsForCameraForStartDataDelivery(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
- return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
- AppOpsManager::OP_NONE, /* forDataDelivery */ true,
- /* startDataDelivery */ true, /* checkAutomotive */ false);
+ return checkPermission(cameraId, sCameraPermission, attributionSource,
+ getAppOpsMessage(cameraId), AppOpsManager::OP_NONE,
+ /* forDataDelivery */ true, /* startDataDelivery */ true,
+ /* checkAutomotive */ false);
}
bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 58c6549..4c243e3 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -223,21 +223,6 @@
static_cast<uint64_t>(1e9 / VirtualCameraDevice::kMinFps));
}
-class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
- public:
- FrameAvailableListenerProxy(std::function<void()> callback)
- : mOnFrameAvailableCallback(callback) {
- }
-
- virtual void onFrameAvailable(const BufferItem&) override {
- ALOGV("%s: onFrameAvailable", __func__);
- mOnFrameAvailableCallback();
- }
-
- private:
- std::function<void()> mOnFrameAvailableCallback;
-};
-
} // namespace
CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -383,10 +368,8 @@
EglTextureProgram::TextureFormat::RGBA);
mEglSurfaceTexture = std::make_unique<EglSurfaceTexture>(
mInputSurfaceSize.width, mInputSurfaceSize.height);
- sp<FrameAvailableListenerProxy> frameAvailableListener =
- sp<FrameAvailableListenerProxy>::make(
- [this]() { requestTextureUpdate(); });
- mEglSurfaceTexture->setFrameAvailableListener(frameAvailableListener);
+ mEglSurfaceTexture->setFrameAvailableListener(
+ [this]() { requestTextureUpdate(); });
mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());
diff --git a/services/camera/virtualcamera/VirtualCameraSession.cc b/services/camera/virtualcamera/VirtualCameraSession.cc
index 88929cc..a5921af 100644
--- a/services/camera/virtualcamera/VirtualCameraSession.cc
+++ b/services/camera/virtualcamera/VirtualCameraSession.cc
@@ -189,7 +189,11 @@
}
halStream.overrideDataSpace = stream.dataSpace;
- halStream.producerUsage = BufferUsage::GPU_RENDER_TARGET;
+ halStream.producerUsage = static_cast<BufferUsage>(
+ static_cast<int64_t>(stream.usage) |
+ static_cast<int64_t>(BufferUsage::CAMERA_OUTPUT) |
+ static_cast<int64_t>(BufferUsage::GPU_RENDER_TARGET));
+
halStream.supportOffline = false;
return halStream;
}
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index fc469a0..f99b965 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -40,6 +40,21 @@
// Maximal number of buffers producer can dequeue without blocking.
constexpr int kBufferProducerMaxDequeueBufferCount = 64;
+class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
+ public:
+ FrameAvailableListenerProxy(const std::function<void()>& callback)
+ : mOnFrameAvailableCallback(callback) {
+ }
+
+ virtual void onFrameAvailable(const BufferItem&) override {
+ ALOGV("%s: onFrameAvailable", __func__);
+ mOnFrameAvailableCallback();
+ }
+
+ private:
+ std::function<void()> mOnFrameAvailableCallback;
+};
+
} // namespace
EglSurfaceTexture::EglSurfaceTexture(const uint32_t width, const uint32_t height)
@@ -92,8 +107,13 @@
}
void EglSurfaceTexture::setFrameAvailableListener(
- const wp<ConsumerBase::FrameAvailableListener>& listener) {
- mGlConsumer->setFrameAvailableListener(listener);
+ const std::function<void()>& listener) {
+ mFrameAvailableListener =
+ sp<FrameAvailableListenerProxy>::make([this, listener]() {
+ mIsFirstFrameDrawn.store(true);
+ listener();
+ });
+ mGlConsumer->setFrameAvailableListener(mFrameAvailableListener);
}
bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
@@ -106,7 +126,7 @@
}
bool EglSurfaceTexture::isFirstFrameDrawn() {
- return mGlConsumer->getFrameNumber() > 0;
+ return mIsFirstFrameDrawn.load();
}
GLuint EglSurfaceTexture::updateTexture() {
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index 9f75315..8b4d45e 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -62,8 +62,7 @@
// Returns false on timeout, true if new frame was received before timeout.
bool waitForNextFrame(std::chrono::nanoseconds timeout);
- void setFrameAvailableListener(
- const wp<ConsumerBase::FrameAvailableListener>& listener);
+ void setFrameAvailableListener(const std::function<void()>& listener);
// Update the texture with the most recent submitted buffer.
// Most be called on thread with EGL context.
@@ -99,6 +98,8 @@
GLuint mTextureId;
const uint32_t mWidth;
const uint32_t mHeight;
+ std::atomic_bool mIsFirstFrameDrawn = false;
+ sp<ConsumerBase::FrameAvailableListener> mFrameAvailableListener;
};
} // namespace virtualcamera
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index c677619..5375934 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -196,14 +196,14 @@
? AAudioConvert_inputPresetToAudioSource(params->getInputPreset())
: AUDIO_SOURCE_DEFAULT;
audio_flags_mask_t flags;
- std::optional<std::string> optTags = {};
+ std::string tags;
if (direction == AAUDIO_DIRECTION_OUTPUT) {
flags = AAudio_computeAudioFlagsMask(
params->getAllowedCapturePolicy(),
params->getSpatializationBehavior(),
params->isContentSpatialized(),
AUDIO_OUTPUT_FLAG_FAST);
- optTags = params->getTags();
+ tags = params->getTagsAsString();
} else {
flags = static_cast<audio_flags_mask_t>(AUDIO_FLAG_LOW_LATENCY
| AAudioConvert_privacySensitiveToAudioFlagsMask(params->isPrivacySensitive()));
@@ -215,9 +215,9 @@
.flags = flags,
.tags = ""
};
- if (optTags.has_value() && !optTags->empty()) {
- strncpy(nativeAttributes.tags, optTags.value().c_str(), AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
- nativeAttributes.tags[AAUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1] = '\0';
+ if (!tags.empty()) {
+ strncpy(nativeAttributes.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE);
+ nativeAttributes.tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1] = '\0';
}
return nativeAttributes;
}