Update APIs for audio attributes tags.
Bug: 378909923
Test: atest test_attributes
Test: libaaudio_fuzzer
Flag: EXEMPT NDK
Change-Id: Iea60b5dca94e4d309d22430913d6f40be0c9eaa0
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/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/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;
}