Merge "libaudiohal@aidl: Fix 'pause' handling" into main
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 116ed9a..d76ed25 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -122,6 +122,10 @@
static sp<IMediaPlayerService> sService;
Mutex mLock;
+ // Static lock was added to the client in order to consume at most
+ // one service thread from image extraction requests of the same
+ // client process(See also b/21277449).
+ static Mutex sLock;
sp<IMediaMetadataRetriever> mRetriever;
};
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 40fd022..9196f9f 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -35,6 +35,8 @@
sp<IMediaPlayerService> MediaMetadataRetriever::sService;
sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
+Mutex MediaMetadataRetriever::sLock;
+
const sp<IMediaPlayerService> MediaMetadataRetriever::getService()
{
Mutex::Autolock lock(sServiceLock);
@@ -143,6 +145,7 @@
ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d) colorFormat(%d) metaOnly(%d)",
timeUs, option, colorFormat, metaOnly);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
@@ -155,6 +158,7 @@
ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
index, colorFormat, metaOnly, thumbnail);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
@@ -167,6 +171,7 @@
ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d) rect {%d, %d, %d, %d}",
index, colorFormat, left, top, right, bottom);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
@@ -180,6 +185,7 @@
ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
index, colorFormat, metaOnly);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
diff --git a/media/module/extractors/Android.bp b/media/module/extractors/Android.bp
index f654ecd..e29d3e6 100644
--- a/media/module/extractors/Android.bp
+++ b/media/module/extractors/Android.bp
@@ -28,6 +28,10 @@
"liblog",
],
+ static_libs: [
+ "libstagefright_metadatautils",
+ ],
+
// extractors are expected to run on Q(29)
min_sdk_version: "29",
apex_available: [
@@ -56,6 +60,7 @@
"libutils",
"libmediandk_format",
"libmedia_ndkformatpriv",
+ "libstagefright_metadatautils",
],
},
},
@@ -68,3 +73,21 @@
],
},
}
+
+aconfig_declarations {
+ name: "android.media.extractor.flags-aconfig",
+ package: "com.android.media.extractor.flags",
+ container: "com.android.media",
+ srcs: ["extractor.aconfig"],
+}
+
+cc_aconfig_library {
+ name: "android.media.extractor.flags-aconfig-cc",
+ aconfig_declarations: "android.media.extractor.flags-aconfig",
+ host_supported: true,
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+}
diff --git a/media/module/extractors/extractor.aconfig b/media/module/extractors/extractor.aconfig
new file mode 100644
index 0000000..c61efa4
--- /dev/null
+++ b/media/module/extractors/extractor.aconfig
@@ -0,0 +1,13 @@
+# Media Extractor flags.
+#
+# !!! Please add flags in alphabetical order. !!!
+package: "com.android.media.extractor.flags"
+container: "com.android.media"
+
+flag {
+ name: "extractor_sniff_midi_optimizations"
+ is_exported: true
+ namespace: "media_extractor"
+ description: "Enable SniffMidi optimizations."
+ bug: "359920208"
+}
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index 7a49d8e..3da1589 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -24,6 +24,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_av_license"],
+ default_team: "trendy_team_android_media_solutions_playback",
}
cc_defaults {
@@ -131,6 +132,7 @@
"libstagefright_id3",
"libstagefright_esds",
"libmp4extractor",
+ "libstagefright_metadatautils",
],
dictionary: "mp4_extractor_fuzzer.dict",
@@ -301,12 +303,18 @@
],
static_libs: [
+ "android.media.extractor.flags-aconfig-cc",
+ "libaconfig_storage_read_api_cc",
"libsonivox",
"libmedia_midiiowrapper",
"libmidiextractor",
"libwatchdog",
],
+ shared_libs: [
+ "server_configurable_flags",
+ ],
+
dictionary: "midi_extractor_fuzzer.dict",
host_supported: true,
diff --git a/media/module/extractors/midi/Android.bp b/media/module/extractors/midi/Android.bp
index feabf9e..0eb34fc 100644
--- a/media/module/extractors/midi/Android.bp
+++ b/media/module/extractors/midi/Android.bp
@@ -32,6 +32,8 @@
],
static_libs: [
+ "android.media.extractor.flags-aconfig-cc",
+ "libaconfig_storage_read_api_cc",
"libmedia_midiiowrapper",
"libsonivoxwithoutjet",
"libstagefright_foundation",
@@ -40,6 +42,7 @@
shared_libs: [
"libbase",
+ "server_configurable_flags",
],
host_supported: true,
diff --git a/media/module/extractors/midi/MidiExtractor.cpp b/media/module/extractors/midi/MidiExtractor.cpp
index 167cc40..98d7716 100644
--- a/media/module/extractors/midi/MidiExtractor.cpp
+++ b/media/module/extractors/midi/MidiExtractor.cpp
@@ -20,6 +20,7 @@
#include "MidiExtractor.h"
+#include <com_android_media_extractor_flags.h>
#include <media/MidiIoWrapper.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
@@ -323,10 +324,97 @@
return AMediaFormat_copy(meta, mFileMetadata);
}
-// Sniffer
+static bool startsWith(const uint8_t *buf, size_t size, const char *pattern, size_t patternSize) {
+ if (size < patternSize) {
+ return false;
+ }
+ return (memcmp(buf, pattern, patternSize) == 0);
+}
-bool SniffMidi(CDataSource *source, float *confidence)
-{
+static bool isValidMThd(const uint8_t *buf, size_t size) {
+ return startsWith(buf, size, "MThd", 4);
+}
+
+static bool isValidXmf(const uint8_t *buf, size_t size) {
+ return startsWith(buf, size, "XMF_", 4);
+}
+
+static bool isValidImelody(const uint8_t *buf, size_t size) {
+ return startsWith(buf, size, "BEGIN:IMELODY", 13);
+}
+
+static bool isValidRtttl(const uint8_t *buf, size_t size) {
+ #define RTTTL_MAX_TITLE_LEN 32
+ // rtttl starts with the following:
+ // <title>:<type>=<value>
+ //
+ // Where:
+ // - <title>: Up to 32 characters
+ // - <type>: Single character indicating:
+ // 'd' for duration
+ // 'o' for octave
+ // 'b' for beats per minute
+ // - <value>: Corresponding value for the type
+ if (size < 4) {
+ return false;
+ }
+ for (size_t i = 0; i < RTTTL_MAX_TITLE_LEN && i < size; i++) {
+ if (buf[i] == ':') {
+ if (i < (size - 3) && buf[i + 2] == '=') {
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+static bool isValidOta(const uint8_t *buf, size_t size) {
+ #define OTA_RINGTONE 0x25
+ #define OTA_SOUND 0x1d
+ #define OTA_UNICODE 0x22
+
+ // ota starts with the following:
+ // <cmdLen><cmd1><cmd2>..<cmdN>
+ //
+ // Where:
+ // - <cmdLen>: Single character command length
+ // - <cmd1>: Single character (OTA_RINGTONE << 1)
+ // - <cmd2>: Single character (OTA_SOUND << 1) or (OTA_UNICODE << 1)
+ // and so on with last cmd being (0x1d << 1)
+
+ if (size < 3) {
+ return false;
+ }
+
+ uint8_t cmdLen = buf[0];
+ if (cmdLen < 2) {
+ return false;
+ }
+
+ if ((buf[1] >> 1) != OTA_RINGTONE) {
+ return false;
+ }
+ cmdLen--;
+
+ size_t i = 2;
+ while(cmdLen && i < size) {
+ switch(buf[i] >> 1) {
+ case OTA_SOUND:
+ return true;
+ case OTA_UNICODE:
+ break;
+ default:
+ return false;
+ }
+ cmdLen--;
+ i++;
+ }
+
+ return false;
+}
+
+bool SniffMidiLegacy(CDataSource *source, float *confidence) {
MidiEngine p(source, NULL, NULL);
if (p.initCheck() == OK) {
*confidence = 0.8;
@@ -335,7 +423,47 @@
}
ALOGV("SniffMidi: no");
return false;
+}
+bool SniffMidiEfficiently(CDataSource *source, float *confidence) {
+ uint8_t header[128];
+ int filled = source->readAt(source->handle, 0, header, sizeof(header));
+
+ if (isValidMThd(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, MThd");
+ return true;
+ }
+ if (isValidXmf(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, XMF_");
+ return true;
+ }
+ if (isValidImelody(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, imelody");
+ return true;
+ }
+ if (isValidRtttl(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, rtttl");
+ return true;
+ }
+ if (isValidOta(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, ota");
+ return true;
+ }
+ ALOGV("SniffMidi: no");
+ return false;
+}
+
+// Sniffer
+bool SniffMidi(CDataSource *source, float *confidence) {
+ if(com::android::media::extractor::flags::extractor_sniff_midi_optimizations()) {
+ return SniffMidiEfficiently(source, confidence);
+ }
+ return SniffMidiLegacy(source, confidence);
}
static const char *extensions[] = {
diff --git a/media/module/extractors/mkv/MatroskaExtractor.cpp b/media/module/extractors/mkv/MatroskaExtractor.cpp
index f326db1..10ae07a 100644
--- a/media/module/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/module/extractors/mkv/MatroskaExtractor.cpp
@@ -1787,7 +1787,7 @@
return ERROR_MALFORMED;
}
- if (!MakeVP9CodecSpecificData(trackInfo->mMeta, tmpData.get(), frame.len)) {
+ if (!MakeVP9CodecSpecificDataFromFirstFrame(trackInfo->mMeta, tmpData.get(), frame.len)) {
return ERROR_MALFORMED;
}
diff --git a/media/module/extractors/mp4/MPEG4Extractor.cpp b/media/module/extractors/mp4/MPEG4Extractor.cpp
index f247f8c..12c0aaf 100644
--- a/media/module/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/module/extractors/mp4/MPEG4Extractor.cpp
@@ -51,6 +51,7 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/MetaDataUtils.h>
#include <utils/String8.h>
#include <byteswap.h>
@@ -2596,8 +2597,32 @@
*offset += chunk_size;
break;
}
-
case FOURCC("vpcC"):
+ {
+ if (mLastTrack == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+
+ if (buffer.get() == NULL) {
+ ALOGE("b/28471206");
+ return NO_MEMORY;
+ }
+
+ if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
+ return ERROR_IO;
+ }
+
+ if (!MakeVP9CodecPrivateFromVpcC(mLastTrack->meta, buffer.get(), chunk_data_size)) {
+ ALOGE("Failed to create VP9 CodecPrivate from vpcC.");
+ return ERROR_MALFORMED;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
case FOURCC("av1C"):
{
auto buffer = heapbuffer<uint8_t>(chunk_data_size);
diff --git a/media/module/metadatautils/MetaDataUtils.cpp b/media/module/metadatautils/MetaDataUtils.cpp
index 0895bb5..177438a 100644
--- a/media/module/metadatautils/MetaDataUtils.cpp
+++ b/media/module/metadatautils/MetaDataUtils.cpp
@@ -134,10 +134,54 @@
}
return true;
}
+
+/**
+ * Build VP9 Codec Feature Metadata (CodecPrivate) to set CSD for VP9 codec.
+ * For reference:
+ * https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate.
+ *
+ * @param meta A pointer to AMediaFormat object.
+ * @param profile The profile value of the VP9 stream.
+ * @param level The VP9 codec level. If the level is unknown, pass -1 to this parameter.
+ * @param bitDepth The bit depth of the luma and color components of the VP9 stream.
+ * @param chromaSubsampling The chroma subsampling of the VP9 stream. If chromaSubsampling is
+ * unknown, pass -1 to this parameter.
+ * @return true if CodecPrivate is set as CSD of AMediaFormat object.
+ *
+ */
+static bool MakeVP9CodecPrivate(AMediaFormat* meta, int32_t profile, int32_t level,
+ int32_t bitDepth, int32_t chromaSubsampling) {
+ if (meta == nullptr) {
+ return false;
+ }
+
+ std::vector<uint8_t> codecPrivate;
+ // Construct CodecPrivate in WebM format (ID | Length | Data).
+ // Helper lambda to add a field to the codec private data
+ auto addField = [&codecPrivate](uint8_t id, uint8_t value) {
+ codecPrivate.push_back(id);
+ codecPrivate.push_back(0x01); // Length is always 1
+ codecPrivate.push_back(value);
+ };
+
+ // Add fields
+ addField(0x01, static_cast<uint8_t>(profile));
+ if (level >= 0) {
+ addField(0x02, static_cast<uint8_t>(level));
+ }
+ addField(0x03, static_cast<uint8_t>(bitDepth));
+ if (chromaSubsampling >= 0) {
+ addField(0x04, static_cast<uint8_t>(chromaSubsampling));
+ }
+ // Set CSD in the meta format
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate.data(), codecPrivate.size());
+ return true;
+}
+
// The param data contains the first frame data, starting with the uncompressed frame
// header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is
// used to parse profile, bitdepth and subsampling.
-bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size) {
+bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size) {
if (meta == nullptr || data == nullptr || size == 0) {
return false;
}
@@ -227,29 +271,29 @@
if (chromaSubsampling != -1) {
csdSize += 3;
}
+ // As level is not present in first frame build CodecPrivate without it.
+ return MakeVP9CodecPrivate(meta, profile, -1, bitDepth, chromaSubsampling);
+}
- // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed
- // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
- sp<ABuffer> csd = sp<ABuffer>::make(csdSize);
- uint8_t* csdData = csd->data();
-
- *csdData++ = 0x01 /* FEATURE PROFILE */;
- *csdData++ = 0x01 /* length */;
- *csdData++ = profile;
-
- *csdData++ = 0x03 /* FEATURE BITDEPTH */;
- *csdData++ = 0x01 /* length */;
- *csdData++ = bitDepth;
-
- // csdSize more than 6 means chroma subsampling data was found.
- if (csdSize > 6) {
- *csdData++ = 0x04 /* FEATURE SUBSAMPLING */;
- *csdData++ = 0x01 /* length */;
- *csdData++ = chromaSubsampling;
+bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* csdData, size_t size) {
+ if (meta == nullptr || csdData == nullptr || size < 12) {
+ return false;
}
- AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd->data(), csd->size());
- return true;
+ // Check the first 4 bytes (VersionAndFlags) if they match the required value.
+ if (csdData[0] != 0x01 || csdData[1] != 0x00 || csdData[2] != 0x00 || csdData[3] != 0x00) {
+ return false;
+ }
+
+ // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed.
+ // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
+ const uint8_t* vpcCData = csdData + 4; // Skip the first 4 bytes (VersionAndFlags)
+
+ int32_t profile = vpcCData[0];
+ int32_t level = vpcCData[1];
+ int32_t bitDepth = (vpcCData[2] >> 4) & 0x0F; // Bit Depth (4 bits).
+ int32_t chromaSubsampling = (vpcCData[2] >> 1) & 0x07; // Chroma Subsampling (3 bits).
+ return MakeVP9CodecPrivate(meta, profile, level, bitDepth, chromaSubsampling);
}
bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
diff --git a/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
index 69cf21a..9988544 100644
--- a/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
+++ b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
@@ -38,7 +38,10 @@
void parseVorbisComment(
AMediaFormat *fileMeta, const char *comment, size_t commentLength);
-bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size);
+bool MakeVP9CodecSpecificData(AMediaFormat* meta, int32_t csdSize, int32_t profile, int32_t level,
+ int32_t bitDepth, int32_t chromaSubsampling);
+bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size);
+bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* data, size_t size);
} // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index ecbd0ae..90d3ef9 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3220,9 +3220,9 @@
// Calculate size of normal sink buffer relative to the HAL output buffer size
double multiplier = 1.0;
- // Note: mType == SPATIALIZER does not support FastMixer.
- if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
- kUseFastMixer == FastMixer_Dynamic)) {
+ // Note: mType == SPATIALIZER does not support FastMixer and DEEP is by definition not "fast"
+ if ((mType == MIXER && !(mOutput->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) &&
+ (kUseFastMixer == FastMixer_Static || kUseFastMixer == FastMixer_Dynamic)) {
size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
size_t maxNormalFrameCount = (kMaxNormalSinkBufferSizeMs * mSampleRate) / 1000;
@@ -5135,7 +5135,16 @@
break;
case FastMixer_Static:
case FastMixer_Dynamic:
- initFastMixer = mFrameCount < mNormalFrameCount;
+ if (mType == MIXER && (output->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
+ /* Do not init fast mixer on deep buffer, warn if buffers are confed too small */
+ initFastMixer = false;
+ ALOGW_IF(mFrameCount * 1000 / mSampleRate < kMinNormalSinkBufferSizeMs,
+ "HAL DEEP BUFFER Buffer (%zu ms) is smaller than set minimal buffer "
+ "(%u ms), seems like a configuration error",
+ mFrameCount * 1000 / mSampleRate, kMinNormalSinkBufferSizeMs);
+ } else {
+ initFastMixer = mFrameCount < mNormalFrameCount;
+ }
break;
}
ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount,
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 3b7cae3..d499222 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -29,19 +29,21 @@
/**
* Legacy audio policy product strategies IDs. These strategies are supported by the default
* policy engine.
+ * IMPORTANT NOTE: the order of this enum is important as it determines the priority
+ * between active strategies for routing decisions: lower enum value => higher prioriy
*/
enum legacy_strategy {
STRATEGY_NONE = -1,
- STRATEGY_MEDIA,
STRATEGY_PHONE,
STRATEGY_SONIFICATION,
- STRATEGY_SONIFICATION_RESPECTFUL,
- STRATEGY_DTMF,
STRATEGY_ENFORCED_AUDIBLE,
- STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
STRATEGY_ACCESSIBILITY,
- STRATEGY_REROUTING,
+ STRATEGY_SONIFICATION_RESPECTFUL,
+ STRATEGY_MEDIA,
+ STRATEGY_DTMF,
STRATEGY_CALL_ASSISTANT,
+ STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
+ STRATEGY_REROUTING,
STRATEGY_PATCH,
};