Merge "Clean upMP3Extractor member data initialization" into rvc-dev
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 8aec80d..9cabd8b 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -614,6 +614,8 @@
// and thus which resulted in an underrun.
virtual uint32_t getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; }
+ virtual uint32_t getUnderrunCount() const { return mCblk->u.mStreaming.mUnderrunCount; }
+
// Return the playback speed and pitch read atomically. Not multi-thread safe on server side.
AudioPlaybackRate getPlaybackRate();
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
new file mode 100644
index 0000000..a6dfb21
--- /dev/null
+++ b/media/TEST_MAPPING
@@ -0,0 +1,32 @@
+{
+ "presubmit": [
+ {
+ "name": "GtsMediaTestCases",
+ "options" : [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ },
+ {
+ "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+ }
+ ]
+ },
+ {
+ "name": "GtsExoPlayerTestCases",
+ "options" : [
+ {
+ "include-annotation": "android.platform.test.annotations.SocPresubmit"
+ },
+ {
+ "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+ }
+ ]
+ }
+ ],
+ "imports": [
+ {
+ "path": "frameworks/av/drm/mediadrm/plugins"
+ }
+ ]
+}
+
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 1947656..cb55b07 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -135,7 +135,14 @@
return false;
}
-uint32_t Accessor::Impl::sSeqId = time(nullptr);
+#ifdef __ANDROID_VNDK__
+static constexpr uint32_t kSeqIdVndkBit = 1 << 31;
+#else
+static constexpr uint32_t kSeqIdVndkBit = 0;
+#endif
+
+static constexpr uint32_t kSeqIdMax = 0x7fffffff;
+uint32_t Accessor::Impl::sSeqId = time(nullptr) & kSeqIdMax;
Accessor::Impl::Impl(
const std::shared_ptr<BufferPoolAllocator> &allocator)
@@ -157,7 +164,7 @@
std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
if (newConnection) {
int32_t pid = getpid();
- ConnectionId id = (int64_t)pid << 32 | sSeqId;
+ ConnectionId id = (int64_t)pid << 32 | sSeqId | kSeqIdVndkBit;
status = mBufferPool.mObserver.open(id, statusDescPtr);
if (status == ResultStatus::OK) {
newConnection->initialize(accessor, id);
@@ -167,7 +174,7 @@
mBufferPool.mConnectionIds.insert(id);
mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
mBufferPool.mInvalidation.onConnect(id, observer);
- if (sSeqId == UINT32_MAX) {
+ if (sSeqId == kSeqIdMax) {
sSeqId = 0;
} else {
++sSeqId;
diff --git a/media/codec2/hidl/1.0/vts/functional/Android.bp b/media/codec2/hidl/1.0/vts/functional/Android.bp
index 5f0ba7d..cd3be81 100644
--- a/media/codec2/hidl/1.0/vts/functional/Android.bp
+++ b/media/codec2/hidl/1.0/vts/functional/Android.bp
@@ -89,6 +89,8 @@
"res/bbb_av1_176_144.av1",
"res/bbb_av1_640_360.info",
"res/bbb_av1_176_144.info",
+ "res/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9",
+ "res/bbb_vp9_704x480_280kbps_24fps_altref_2.info",
],
}
diff --git a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index 5d4b001..da8225c 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -115,7 +115,8 @@
typedef std::unique_lock<std::mutex> ULock;
ULock l(queueLock);
workQueue.push_back(std::move(work));
- if (!flushedIndices.empty()) {
+ if (!flushedIndices.empty() &&
+ (frameIndexIt != flushedIndices.end())) {
flushedIndices.erase(frameIndexIt);
}
queueCondition.notify_all();
diff --git a/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp b/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
index 119ce14..6122225 100644
--- a/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/component/VtsHalMediaC2V1_0TargetComponentTest.cpp
@@ -330,7 +330,7 @@
TEST_P(Codec2ComponentInputTests, InputBufferTest) {
description("Tests for different inputs");
- uint32_t flags = std::stol(std::get<2>(GetParam()));
+ uint32_t flags = std::stoul(std::get<2>(GetParam()));
bool isNullBuffer = !std::get<3>(GetParam()).compare("true");
if (isNullBuffer)
ALOGD("Testing for null input buffer with flag : %u", flags);
diff --git a/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.info
new file mode 100644
index 0000000..9ea1ffa
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.info
@@ -0,0 +1,352 @@
+73 0 0
+159 16 41000
+103 16 41000
+34 0 41000
+30 0 83000
+30 0 125000
+30 0 166000
+1 0 208000
+105 0 250000
+54 0 291000
+65 0 333000
+1 0 375000
+239 0 416000
+1373 16 458000
+263 16 458000
+133 0 458000
+109 0 500000
+127 0 541000
+1 0 583000
+134 0 625000
+159 0 666000
+131 0 708000
+1 0 750000
+4420 16 791000
+349 16 791000
+151 0 791000
+1 0 833000
+120 0 875000
+1 0 916000
+3203 16 958000
+433 16 958000
+125 0 958000
+1 0 1000000
+107 0 1041000
+1 0 1083000
+3832 16 1125000
+541 16 1125000
+116 0 1125000
+1 0 1166000
+115 0 1208000
+1 0 1250000
+3777 16 1291000
+495 16 1291000
+109 0 1291000
+1 0 1333000
+79 0 1375000
+1 0 1416000
+3906 16 1458000
+539 16 1458000
+149 0 1458000
+1 0 1500000
+112 0 1541000
+1 0 1583000
+5495 16 1625000
+594 16 1625000
+392 0 1625000
+235 0 1666000
+170 0 1708000
+1 0 1750000
+384 0 1791000
+378 0 1833000
+120 0 1875000
+1 0 1916000
+16843 16 1958000
+1951 16 1958000
+774 0 1958000
+831 0 2000000
+560 0 2041000
+489 0 2083000
+345 0 2125000
+243 0 2166000
+260 0 2208000
+1 0 2250000
+498 0 2291000
+463 0 2333000
+414 0 2375000
+341 0 2416000
+262 0 2458000
+194 0 2500000
+85 0 2541000
+1 0 2583000
+11253 16 2625000
+1561 16 2625000
+250 0 2625000
+402 0 2666000
+454 0 2708000
+350 0 2750000
+316 0 2791000
+164 0 2833000
+108 0 2875000
+1 0 2916000
+246 0 2958000
+586 0 3000000
+493 0 3041000
+363 0 3083000
+325 0 3125000
+170 0 3166000
+78 0 3208000
+40 0 3250000
+15630 16 3291000
+2228 16 3291000
+346 0 3291000
+707 0 3333000
+685 0 3375000
+582 0 3416000
+473 0 3458000
+249 0 3500000
+177 0 3541000
+1 0 3583000
+541 0 3625000
+834 0 3666000
+614 0 3708000
+473 0 3750000
+365 0 3791000
+211 0 3833000
+91 0 3875000
+1 0 3916000
+8384 16 3958000
+1138 16 3958000
+256 0 3958000
+377 0 4000000
+316 0 4041000
+267 0 4083000
+119 0 4125000
+1 0 4166000
+319 0 4208000
+390 0 4250000
+243 0 4291000
+203 0 4333000
+110 0 4375000
+1 0 4416000
+11302 16 4458000
+1527 16 4458000
+408 0 4458000
+507 0 4500000
+350 0 4541000
+377 0 4583000
+239 0 4625000
+125 0 4666000
+1 0 4708000
+351 0 4750000
+469 0 4791000
+288 0 4833000
+244 0 4875000
+224 0 4916000
+108 0 4958000
+1 0 5000000
+6016 16 5041000
+561 16 5041000
+235 0 5041000
+213 0 5083000
+118 0 5125000
+1 0 5166000
+299 0 5208000
+213 0 5250000
+129 0 5291000
+1 0 5333000
+7029 16 5375000
+728 16 5375000
+339 0 5375000
+287 0 5416000
+225 0 5458000
+147 0 5500000
+1 0 5541000
+270 0 5583000
+217 0 5625000
+138 0 5666000
+46 0 5708000
+32861 0 5750000
+16095 16 5791000
+2033 16 5791000
+318 0 5791000
+443 0 5833000
+361 0 5875000
+313 0 5916000
+274 0 5958000
+210 0 6000000
+134 0 6041000
+1 0 6083000
+295 0 6125000
+415 0 6166000
+330 0 6208000
+264 0 6250000
+242 0 6291000
+166 0 6333000
+116 0 6375000
+1 0 6416000
+9488 16 6458000
+1466 16 6458000
+378 0 6458000
+419 0 6500000
+335 0 6541000
+290 0 6583000
+315 0 6625000
+199 0 6666000
+131 0 6708000
+1 0 6750000
+342 0 6791000
+421 0 6833000
+306 0 6875000
+320 0 6916000
+245 0 6958000
+205 0 7000000
+143 0 7041000
+1 0 7083000
+16554 16 7125000
+1744 16 7125000
+482 0 7125000
+365 0 7166000
+352 0 7208000
+308 0 7250000
+295 0 7291000
+199 0 7333000
+149 0 7375000
+1 0 7416000
+360 0 7458000
+428 0 7500000
+377 0 7541000
+347 0 7583000
+270 0 7625000
+187 0 7666000
+130 0 7708000
+39 0 7750000
+14637 16 7791000
+1832 16 7791000
+422 0 7791000
+466 0 7833000
+375 0 7875000
+405 0 7916000
+352 0 7958000
+275 0 8000000
+173 0 8041000
+1 0 8083000
+484 0 8125000
+516 0 8166000
+497 0 8208000
+452 0 8250000
+428 0 8291000
+293 0 8333000
+190 0 8375000
+1 0 8416000
+11534 16 8458000
+1655 16 8458000
+446 0 8458000
+531 0 8500000
+465 0 8541000
+495 0 8583000
+402 0 8625000
+330 0 8666000
+227 0 8708000
+1 0 8750000
+568 0 8791000
+694 0 8833000
+382 0 8875000
+422 0 8916000
+280 0 8958000
+305 0 9000000
+203 0 9041000
+1 0 9083000
+17067 16 9125000
+1521 16 9125000
+428 0 9125000
+434 0 9166000
+359 0 9208000
+368 0 9250000
+240 0 9291000
+215 0 9333000
+211 0 9375000
+1 0 9416000
+346 0 9458000
+533 0 9500000
+391 0 9541000
+313 0 9583000
+326 0 9625000
+211 0 9666000
+233 0 9708000
+35 0 9750000
+23743 16 9791000
+1968 16 9791000
+277 0 9791000
+276 0 9833000
+285 0 9875000
+232 0 9916000
+179 0 9958000
+203 0 10000000
+121 0 10041000
+1 0 10083000
+318 0 10125000
+391 0 10166000
+362 0 10208000
+291 0 10250000
+235 0 10291000
+187 0 10333000
+117 0 10375000
+43 0 10416000
+12465 16 10458000
+1607 16 10458000
+280 0 10458000
+295 0 10500000
+244 0 10541000
+211 0 10583000
+171 0 10625000
+159 0 10666000
+106 0 10708000
+1 0 10750000
+216 0 10791000
+195 0 10833000
+180 0 10875000
+164 0 10916000
+156 0 10958000
+96 0 11000000
+1 0 11041000
+54547 0 11083000
+2920 16 11125000
+153 16 11125000
+117 0 11125000
+83 0 11166000
+86 0 11208000
+1 0 11250000
+92 0 11291000
+93 0 11333000
+80 0 11375000
+1 0 11416000
+1314 16 11458000
+311 16 11458000
+79 0 11458000
+65 0 11500000
+74 0 11541000
+61 0 11583000
+1 0 11625000
+65 0 11666000
+64 0 11708000
+49 0 11750000
+51 0 11791000
+1 0 11833000
+19309 0 11875000
+3848 16 11916000
+771 16 11916000
+167 0 11916000
+202 0 11958000
+190 0 12000000
+173 0 12041000
+128 0 12083000
+79 0 12125000
+1 0 12166000
+155 0 12208000
+211 0 12250000
+192 0 12291000
+131 0 12333000
+91 0 12375000
+128 0 12416000
+1 0 12458000
diff --git a/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9
new file mode 100644
index 0000000..00c7dec
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index ec3fd7b..f216429 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -267,7 +267,7 @@
}
// number of elementary streams per component
-#define STREAM_COUNT 2
+#define STREAM_COUNT 3
// LookUpTable of clips and metadata for component testing
void GetURLForComponent(Codec2VideoDecHidlTest::standardComp comp, char* mURL, char* info,
size_t streamIndex = 1) {
@@ -280,29 +280,31 @@
static const CompToURL kCompToURL[] = {
{Codec2VideoDecHidlTest::standardComp::avc,
- {"bbb_avc_176x144_300kbps_60fps.h264", "bbb_avc_640x360_768kbps_30fps.h264"},
- {"bbb_avc_176x144_300kbps_60fps.info", "bbb_avc_640x360_768kbps_30fps.info"}},
+ {"bbb_avc_176x144_300kbps_60fps.h264", "bbb_avc_640x360_768kbps_30fps.h264", ""},
+ {"bbb_avc_176x144_300kbps_60fps.info", "bbb_avc_640x360_768kbps_30fps.info", ""}},
{Codec2VideoDecHidlTest::standardComp::hevc,
- {"bbb_hevc_176x144_176kbps_60fps.hevc", "bbb_hevc_640x360_1600kbps_30fps.hevc"},
- {"bbb_hevc_176x144_176kbps_60fps.info", "bbb_hevc_640x360_1600kbps_30fps.info"}},
+ {"bbb_hevc_176x144_176kbps_60fps.hevc", "bbb_hevc_640x360_1600kbps_30fps.hevc", ""},
+ {"bbb_hevc_176x144_176kbps_60fps.info", "bbb_hevc_640x360_1600kbps_30fps.info", ""}},
{Codec2VideoDecHidlTest::standardComp::mpeg2,
- {"bbb_mpeg2_176x144_105kbps_25fps.m2v", "bbb_mpeg2_352x288_1mbps_60fps.m2v"},
- {"bbb_mpeg2_176x144_105kbps_25fps.info", "bbb_mpeg2_352x288_1mbps_60fps.info"}},
+ {"bbb_mpeg2_176x144_105kbps_25fps.m2v", "bbb_mpeg2_352x288_1mbps_60fps.m2v", ""},
+ {"bbb_mpeg2_176x144_105kbps_25fps.info", "bbb_mpeg2_352x288_1mbps_60fps.info", ""}},
{Codec2VideoDecHidlTest::standardComp::h263,
- {"", "bbb_h263_352x288_300kbps_12fps.h263"},
- {"", "bbb_h263_352x288_300kbps_12fps.info"}},
+ {"", "bbb_h263_352x288_300kbps_12fps.h263", ""},
+ {"", "bbb_h263_352x288_300kbps_12fps.info", ""}},
{Codec2VideoDecHidlTest::standardComp::mpeg4,
- {"", "bbb_mpeg4_352x288_512kbps_30fps.m4v"},
- {"", "bbb_mpeg4_352x288_512kbps_30fps.info"}},
+ {"", "bbb_mpeg4_352x288_512kbps_30fps.m4v", ""},
+ {"", "bbb_mpeg4_352x288_512kbps_30fps.info", ""}},
{Codec2VideoDecHidlTest::standardComp::vp8,
- {"bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_640x360_2mbps_30fps.vp8"},
- {"bbb_vp8_176x144_240kbps_60fps.info", "bbb_vp8_640x360_2mbps_30fps.info"}},
+ {"bbb_vp8_176x144_240kbps_60fps.vp8", "bbb_vp8_640x360_2mbps_30fps.vp8", ""},
+ {"bbb_vp8_176x144_240kbps_60fps.info", "bbb_vp8_640x360_2mbps_30fps.info", ""}},
{Codec2VideoDecHidlTest::standardComp::vp9,
- {"bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_640x360_1600kbps_30fps.vp9"},
- {"bbb_vp9_176x144_285kbps_60fps.info", "bbb_vp9_640x360_1600kbps_30fps.info"}},
+ {"bbb_vp9_176x144_285kbps_60fps.vp9", "bbb_vp9_640x360_1600kbps_30fps.vp9",
+ "bbb_vp9_704x480_280kbps_24fps_altref_2.vp9"},
+ {"bbb_vp9_176x144_285kbps_60fps.info", "bbb_vp9_640x360_1600kbps_30fps.info",
+ "bbb_vp9_704x480_280kbps_24fps_altref_2.info"}},
{Codec2VideoDecHidlTest::standardComp::av1,
- {"bbb_av1_640_360.av1", "bbb_av1_176_144.av1"},
- {"bbb_av1_640_360.info", "bbb_av1_176_144.info"}},
+ {"bbb_av1_640_360.av1", "bbb_av1_176_144.av1", ""},
+ {"bbb_av1_640_360.info", "bbb_av1_176_144.info", ""}},
};
for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
@@ -481,7 +483,9 @@
eleInfo >> flags;
eleInfo >> timestamp;
bool codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
- if (mTimestampDevTest && !codecConfig) mTimestampUslist.push_back(timestamp);
+ bool nonDisplayFrame = ((flags & FLAG_NON_DISPLAY_FRAME) != 0);
+ if (mTimestampDevTest && !codecConfig && !nonDisplayFrame)
+ mTimestampUslist.push_back(timestamp);
Info.push_back({bytesCount, flags, timestamp});
}
eleInfo.close();
@@ -545,6 +549,10 @@
strcpy(mURL, sResourceDir.c_str());
strcpy(info, sResourceDir.c_str());
GetURLForComponent(mCompName, mURL, info, i % STREAM_COUNT);
+ if (!(strcmp(mURL, sResourceDir.c_str())) || !(strcmp(info, sResourceDir.c_str()))) {
+ ALOGV("Stream not available, skipping this index");
+ continue;
+ }
eleInfo.open(info);
ASSERT_EQ(eleInfo.is_open(), true) << mURL << " - file not found";
@@ -560,10 +568,12 @@
Info.push_back({bytesCount, flags, timestamp});
bool codecConfig =
flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+ bool nonDisplayFrame = ((flags & FLAG_NON_DISPLAY_FRAME) != 0);
{
ULock l(mQueueLock);
- if (mTimestampDevTest && !codecConfig) mTimestampUslist.push_back(timestamp);
+ if (mTimestampDevTest && !codecConfig && !nonDisplayFrame)
+ mTimestampUslist.push_back(timestamp);
}
if (timestampMax < timestamp) timestampMax = timestamp;
}
@@ -903,6 +913,10 @@
std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "false"));
kDecodeTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "1", "true"));
+ kDecodeTestParameters.push_back(
+ std::make_tuple(std::get<0>(params), std::get<1>(params), "2", "false"));
+ kDecodeTestParameters.push_back(
+ std::make_tuple(std::get<0>(params), std::get<1>(params), "2", "true"));
}
// Set the resource directory based on command line args.
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.xml b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.xml
index 8761797..63e7a69 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.xml
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.xml
@@ -49,6 +49,8 @@
<option name="push-file" key="bbb_av1_176_144.av1" value="/data/local/tmp/media/bbb_av1_176_144.av1" />
<option name="push-file" key="bbb_av1_640_360.info" value="/data/local/tmp/media/bbb_av1_640_360.info" />
<option name="push-file" key="bbb_av1_176_144.info" value="/data/local/tmp/media/bbb_av1_176_144.info" />
+ <option name="push-file" key="bbb_vp9_704x480_280kbps_24fps_altref_2.vp9" value="/data/local/tmp/media/bbb_vp9_704x480_280kbps_24fps_altref_2.vp9" />
+ <option name="push-file" key="bbb_vp9_704x480_280kbps_24fps_altref_2.info" value="/data/local/tmp/media/bbb_vp9_704x480_280kbps_24fps_altref_2.info" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
diff --git a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index be97383..ecc56f5 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -41,7 +41,8 @@
: C2Buffer({block->share(C2Rect(block->width(), block->height()), ::C2Fence())}) {}
};
-static std::vector<std::tuple<std::string, std::string, std::string>> kEncodeTestParameters;
+static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
+ kEncodeTestParameters;
static std::vector<std::tuple<std::string, std::string, std::string, std::string>>
kEncodeResolutionTestParameters;
@@ -102,6 +103,7 @@
mFramesReceived = 0;
mFailedWorkReceived = 0;
mTimestampUs = 0u;
+ mOutputSize = 0u;
mTimestampDevTest = false;
if (mCompName == unknown_comp) mDisableTest = true;
if (mDisableTest) std::cout << "[ WARN ] Test Disabled \n";
@@ -159,6 +161,16 @@
}
if (work->result != C2_OK) mFailedWorkReceived++;
+ if (!work->worklets.front()->output.buffers.empty()) {
+ mOutputSize += work->worklets.front()
+ ->output.buffers[0]
+ ->data()
+ .linearBlocks()
+ .front()
+ .map()
+ .get()
+ .capacity();
+ }
workDone(mComponent, work, mFlushedIndices, mQueueLock, mQueueCondition, mWorkQueue,
mEos, mCsd, mFramesReceived);
}
@@ -186,6 +198,7 @@
uint32_t mFramesReceived;
uint32_t mFailedWorkReceived;
uint64_t mTimestampUs;
+ uint64_t mOutputSize;
std::list<uint64_t> mTimestampUslist;
std::list<uint64_t> mFlushedIndices;
@@ -281,7 +294,6 @@
uint32_t maxRetry = 0;
int bytesCount = nWidth * nHeight * 3 >> 1;
int32_t timestampIncr = ENCODER_TIMESTAMP_INCREMENT;
- uint64_t timestamp = 0;
c2_status_t err = C2_OK;
while (1) {
if (nFrames == 0) break;
@@ -308,7 +320,7 @@
}
work->input.flags = (C2FrameData::flags_t)flags;
- work->input.ordinal.timestamp = timestamp;
+ work->input.ordinal.timestamp = frameID * timestampIncr;
work->input.ordinal.frameIndex = frameID;
{
ULock l(queueLock);
@@ -361,7 +373,6 @@
ASSERT_EQ(component->queue(&items), C2_OK);
ALOGV("Frame #%d size = %d queued", frameID, bytesCount);
nFrames--;
- timestamp += timestampIncr;
frameID++;
maxRetry = 0;
}
@@ -376,7 +387,8 @@
class Codec2VideoEncEncodeTest
: public Codec2VideoEncHidlTestBase,
- public ::testing::WithParamInterface<std::tuple<std::string, std::string, std::string>> {
+ public ::testing::WithParamInterface<
+ std::tuple<std::string, std::string, std::string, std::string>> {
void getParams() {
mInstanceName = std::get<0>(GetParam());
mComponentName = std::get<1>(GetParam());
@@ -391,6 +403,8 @@
int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
bool signalEOS = !std::get<2>(GetParam()).compare("true");
+ // Send an empty frame to receive CSD data from encoder.
+ bool sendEmptyFirstFrame = !std::get<3>(GetParam()).compare("true");
strcpy(mURL, sResourceDir.c_str());
GetURLForComponent(mURL);
@@ -404,24 +418,32 @@
mTimestampDevTest = true;
mFlushedIndices.clear();
mTimestampUslist.clear();
- uint32_t inputFrames = ENC_NUM_FRAMES;
+ int32_t inputFrames = ENC_NUM_FRAMES + (sendEmptyFirstFrame ? 1 : 0);
uint32_t timestamp = 0;
+
// Add input timestamp to timestampUslist
while (inputFrames) {
if (mTimestampDevTest) mTimestampUslist.push_back(timestamp);
timestamp += ENCODER_TIMESTAMP_INCREMENT;
inputFrames--;
}
+
if (!setupConfigParam(nWidth, nHeight)) {
std::cout << "[ WARN ] Test Skipped \n";
return;
}
ASSERT_EQ(mComponent->start(), C2_OK);
+
+ if (sendEmptyFirstFrame) {
+ ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue, 0, false));
+ inputFrames += 1;
+ }
ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
- mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 0,
- ENC_NUM_FRAMES, nWidth, nHeight, false, signalEOS));
+ mFlushedIndices, mGraphicPool, eleStream, mDisableTest,
+ inputFrames, ENC_NUM_FRAMES, nWidth, nHeight, false,
+ signalEOS));
// mDisableTest will be set if buffer was not fetched properly.
- // This may happen when resolution is not proper but config suceeded
+ // This may happen when resolution is not proper but config succeeded
// In this cases, we skip encoding the input stream
if (mDisableTest) {
std::cout << "[ WARN ] Test Disabled \n";
@@ -430,7 +452,7 @@
}
// If EOS is not sent, sending empty input with EOS flag
- inputFrames = ENC_NUM_FRAMES;
+ inputFrames += ENC_NUM_FRAMES;
if (!signalEOS) {
ASSERT_NO_FATAL_FAILURE(waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue, 1));
ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
@@ -531,7 +553,7 @@
mFlushedIndices, mGraphicPool, eleStream, mDisableTest, 0,
numFramesFlushed, nWidth, nHeight));
// mDisableTest will be set if buffer was not fetched properly.
- // This may happen when resolution is not proper but config suceeded
+ // This may happen when resolution is not proper but config succeeded
// In this cases, we skip encoding the input stream
if (mDisableTest) {
std::cout << "[ WARN ] Test Disabled \n";
@@ -568,7 +590,7 @@
nHeight, true));
eleStream.close();
// mDisableTest will be set if buffer was not fetched properly.
- // This may happen when resolution is not proper but config suceeded
+ // This may happen when resolution is not proper but config succeeded
// In this cases, we skip encoding the input stream
if (mDisableTest) {
std::cout << "[ WARN ] Test Disabled \n";
@@ -677,7 +699,7 @@
MAX_INPUT_BUFFERS, nWidth, nHeight, false, true));
// mDisableTest will be set if buffer was not fetched properly.
- // This may happen when resolution is not proper but config suceeded
+ // This may happen when resolution is not proper but config succeeded
// In this cases, we skip encoding the input stream
if (mDisableTest) {
std::cout << "[ WARN ] Test Disabled \n";
@@ -703,15 +725,105 @@
INSTANTIATE_TEST_SUITE_P(EncodeTestwithEOS, Codec2VideoEncEncodeTest,
::testing::ValuesIn(kEncodeTestParameters));
+TEST_P(Codec2VideoEncHidlTest, AdaptiveBitrateTest) {
+ description("Encodes input file for different bitrates");
+ if (mDisableTest) GTEST_SKIP() << "Test is disabled";
+
+ char mURL[512];
+
+ strcpy(mURL, sResourceDir.c_str());
+ GetURLForComponent(mURL);
+
+ std::ifstream eleStream;
+ eleStream.open(mURL, std::ifstream::binary);
+ ASSERT_EQ(eleStream.is_open(), true) << mURL << " file not found";
+ ALOGV("mURL : %s", mURL);
+
+ mFlushedIndices.clear();
+
+ int32_t nWidth = ENC_DEFAULT_FRAME_WIDTH;
+ int32_t nHeight = ENC_DEFAULT_FRAME_HEIGHT;
+ if (!setupConfigParam(nWidth, nHeight)) {
+ std::cout << "[ WARN ] Test Skipped \n";
+ return;
+ }
+ ASSERT_EQ(mComponent->start(), C2_OK);
+
+ uint64_t prevOutputSize = 0u;
+ uint32_t bitrateValues[] = {100000, 64000, 200000};
+ uint32_t prevBitrate = 0;
+ int32_t inputFrameId = 0;
+
+ for (uint32_t curBitrate : bitrateValues) {
+ // Configuring bitrate
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ C2StreamBitrateInfo::output bitrate(0u, curBitrate);
+ std::vector<C2Param*> configParam{&bitrate};
+ c2_status_t status = mComponent->config(configParam, C2_DONT_BLOCK, &failures);
+ if (status != C2_OK && failures.size() != 0u) {
+ ALOGW("BitRate Config failed, using previous bitrate");
+ }
+
+ ASSERT_NO_FATAL_FAILURE(encodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
+ mFlushedIndices, mGraphicPool, eleStream,
+ mDisableTest, inputFrameId, ENC_NUM_FRAMES, nWidth,
+ nHeight, false, false));
+ // mDisableTest will be set if buffer was not fetched properly.
+ // This may happen when resolution is not proper but config succeeded
+ // In this cases, we skip encoding the input stream
+ if (mDisableTest) {
+ std::cout << "[ WARN ] Test Disabled \n";
+ ASSERT_EQ(mComponent->stop(), C2_OK);
+ return;
+ }
+ inputFrameId += ENC_NUM_FRAMES;
+ // blocking call to ensures application to Wait till all the inputs are
+ // consumed
+ ALOGD("Waiting for input consumption");
+ waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue);
+
+ // Change in bitrate may result in different outputSize
+ if (prevBitrate >= curBitrate) {
+ EXPECT_LE(mOutputSize, prevOutputSize);
+ } else {
+ EXPECT_GE(mOutputSize, prevOutputSize);
+ }
+ prevBitrate = curBitrate;
+ prevOutputSize = mOutputSize;
+ // Reset the file pointer and output size
+ mOutputSize = 0;
+ eleStream.seekg(0, eleStream.beg);
+ }
+
+ // Sending empty input with EOS flag
+ ASSERT_NO_FATAL_FAILURE(testInputBuffer(mComponent, mQueueLock, mWorkQueue,
+ C2FrameData::FLAG_END_OF_STREAM, false));
+ inputFrameId += 1;
+ waitOnInputConsumption(mQueueLock, mQueueCondition, mWorkQueue);
+
+ eleStream.close();
+ if (mFramesReceived != inputFrameId) {
+ ALOGE("Input buffer count and Output buffer count mismatch");
+ ALOGE("framesReceived : %d inputFrames : %d", mFramesReceived, inputFrameId);
+ ASSERT_TRUE(false);
+ }
+
+ ASSERT_EQ(mComponent->stop(), C2_OK);
+}
+
} // anonymous namespace
int main(int argc, char** argv) {
kTestParameters = getTestParameters(C2Component::DOMAIN_VIDEO, C2Component::KIND_ENCODER);
for (auto params : kTestParameters) {
kEncodeTestParameters.push_back(
- std::make_tuple(std::get<0>(params), std::get<1>(params), "true"));
+ std::make_tuple(std::get<0>(params), std::get<1>(params), "true", "true"));
kEncodeTestParameters.push_back(
- std::make_tuple(std::get<0>(params), std::get<1>(params), "false"));
+ std::make_tuple(std::get<0>(params), std::get<1>(params), "true", "false"));
+ kEncodeTestParameters.push_back(
+ std::make_tuple(std::get<0>(params), std::get<1>(params), "false", "true"));
+ kEncodeTestParameters.push_back(
+ std::make_tuple(std::get<0>(params), std::get<1>(params), "false", "false"));
kEncodeResolutionTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "52", "18"));
@@ -721,6 +833,10 @@
std::make_tuple(std::get<0>(params), std::get<1>(params), "484", "362"));
kEncodeResolutionTestParameters.push_back(
std::make_tuple(std::get<0>(params), std::get<1>(params), "244", "488"));
+ kEncodeResolutionTestParameters.push_back(
+ std::make_tuple(std::get<0>(params), std::get<1>(params), "852", "608"));
+ kEncodeResolutionTestParameters.push_back(
+ std::make_tuple(std::get<0>(params), std::get<1>(params), "1400", "442"));
}
// Set the resource directory based on command line args.
@@ -734,4 +850,4 @@
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
-}
\ No newline at end of file
+}
diff --git a/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
index d3a693b..9c1a5cb 100644
--- a/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
@@ -22,6 +22,7 @@
#define ENC_DEFAULT_FRAME_WIDTH 352
#define ENC_DEFAULT_FRAME_HEIGHT 288
#define MAX_ITERATIONS 128
+#define FLAG_NON_DISPLAY_FRAME (1 << 4)
#define ALIGN(_sz, _align) ((_sz + (_align - 1)) & ~(_align - 1))
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index e902b5d..3773528 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -1705,8 +1705,8 @@
}
}
- if (!buffer && !flags) {
- ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
+ if (!buffer && !flags && outputFormat == nullptr) {
+ ALOGV("[%s] onWorkDone: nothing to report from the work (%lld)",
mName, work->input.ordinal.frameIndex.peekull());
return true;
}
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 3ac3d89..e1e1377 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -520,6 +520,22 @@
break;
}
+ case static_cast<uint32_t>(PixelFormat4::BLOB): {
+ void *pointer = nullptr;
+ // TODO: fence
+ status_t err = GraphicBufferMapper::get().lock(
+ const_cast<native_handle_t*>(mBuffer), grallocUsage,
+ { (int32_t)rect.left, (int32_t)rect.top,
+ (int32_t)rect.width, (int32_t)rect.height },
+ &pointer);
+ if (err) {
+ ALOGE("failed transaction: lock(BLOB)");
+ return C2_CORRUPTED;
+ }
+ *addr = (uint8_t *)pointer;
+ break;
+ }
+
case static_cast<uint32_t>(PixelFormat4::YCBCR_420_888):
// fall-through
case static_cast<uint32_t>(PixelFormat4::YV12):
diff --git a/media/libmedia/aidl/android/media/IResourceManagerService.aidl b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
index 3dd0859..1b2d522 100644
--- a/media/libmedia/aidl/android/media/IResourceManagerService.aidl
+++ b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
@@ -94,4 +94,12 @@
* remove existing override on originalPid if newPid is -1.
*/
void overridePid(int originalPid, int newPid);
+
+ /**
+ * Mark a client for pending removal
+ *
+ * @param pid pid from which the client's resources will be removed.
+ * @param clientId clientId within the pid that will be removed.
+ */
+ void markClientForPendingRemoval(int pid, long clientId);
}
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 00da69a..ec0e133 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -37,6 +37,11 @@
// They must be appended with another value to make a key.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio."
+// The AudioMmap key appends the "trackId" to the prefix.
+// This is the AudioFlinger equivalent of the AAudio Stream.
+// TODO: unify with AMEDIAMETRICS_KEY_PREFIX_AUDIO_STREAM
+#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP AMEDIAMETRICS_KEY_PREFIX_AUDIO "mmap."
+
// The AudioRecord key appends the "trackId" to the prefix.
#define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record."
@@ -95,6 +100,14 @@
#define AMEDIAMETRICS_PROP_CHANNELCOUNT "channelCount" // int32
#define AMEDIAMETRICS_PROP_CHANNELMASK "channelMask" // int32
#define AMEDIAMETRICS_PROP_CONTENTTYPE "contentType" // string attributes (AudioTrack)
+#define AMEDIAMETRICS_PROP_CUMULATIVETIMENS "cumulativeTimeNs" // int64_t playback/record time
+ // since start
+// DEVICE values are averaged since starting on device
+#define AMEDIAMETRICS_PROP_DEVICELATENCYMS "deviceLatencyMs" // double - avg latency time
+#define AMEDIAMETRICS_PROP_DEVICESTARTUPMS "deviceStartupMs" // double - avg startup time
+#define AMEDIAMETRICS_PROP_DEVICETIMENS "deviceTimeNs" // int64_t playback/record time
+#define AMEDIAMETRICS_PROP_DEVICEVOLUME "deviceVolume" // double - average device volume
+
#define AMEDIAMETRICS_PROP_DIRECTION "direction" // string AAudio input or output
#define AMEDIAMETRICS_PROP_DURATIONNS "durationNs" // int64 duration time span
#define AMEDIAMETRICS_PROP_ENCODING "encoding" // string value of format
@@ -105,7 +118,9 @@
#define AMEDIAMETRICS_PROP_FRAMECOUNT "frameCount" // int32
#define AMEDIAMETRICS_PROP_INPUTDEVICES "inputDevices" // string value
+#define AMEDIAMETRICS_PROP_INTERVALCOUNT "intervalCount" // int32
#define AMEDIAMETRICS_PROP_LATENCYMS "latencyMs" // double value
+#define AMEDIAMETRICS_PROP_NAME "name" // string value
#define AMEDIAMETRICS_PROP_ORIGINALFLAGS "originalFlags" // int32
#define AMEDIAMETRICS_PROP_OUTPUTDEVICES "outputDevices" // string value
#define AMEDIAMETRICS_PROP_PERFORMANCEMODE "performanceMode" // string value, "none", lowLatency"
@@ -129,6 +144,7 @@
#define AMEDIAMETRICS_PROP_TRACKID "trackId" // int32 port id of track/record
#define AMEDIAMETRICS_PROP_TYPE "type" // string (thread type)
#define AMEDIAMETRICS_PROP_UNDERRUN "underrun" // int32
+#define AMEDIAMETRICS_PROP_UNDERRUNFRAMES "underrunFrames" // int64_t from Thread
#define AMEDIAMETRICS_PROP_USAGE "usage" // string attributes (ATrack)
#define AMEDIAMETRICS_PROP_VOLUME_LEFT "volume.left" // double (AudioTrack)
#define AMEDIAMETRICS_PROP_VOLUME_RIGHT "volume.right" // double (AudioTrack)
@@ -140,12 +156,14 @@
// Values are strings accepted for a given property.
// An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP "beginAudioIntervalGroup"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE "close"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE "create"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH "createAudioPatch"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR "ctor"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_DISCONNECT "disconnect"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR "dtor"
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP "endAudioIntervalGroup"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_FLUSH "flush" // AudioTrack
#define AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE "invalidate" // server track, record
#define AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN "open"
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b597583..11f2f38 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -199,6 +199,7 @@
void addResource(const MediaResourceParcel &resource);
void removeResource(const MediaResourceParcel &resource);
void removeClient();
+ void markClientForPendingRemoval();
bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
private:
@@ -280,6 +281,14 @@
mService->removeClient(mPid, getId(mClient));
}
+void MediaCodec::ResourceManagerServiceProxy::markClientForPendingRemoval() {
+ Mutex::Autolock _l(mLock);
+ if (mService == nullptr) {
+ return;
+ }
+ mService->markClientForPendingRemoval(mPid, getId(mClient));
+}
+
bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
const std::vector<MediaResourceParcel> &resources) {
Mutex::Autolock _l(mLock);
@@ -297,6 +306,33 @@
////////////////////////////////////////////////////////////////////////////////
+class MediaCodec::ReleaseSurface {
+public:
+ ReleaseSurface() {
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ mSurface = new Surface(mProducer, false /* controlledByApp */);
+ struct ConsumerListener : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem&) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+ sp<ConsumerListener> listener{new ConsumerListener};
+ mConsumer->consumerConnect(listener, false);
+ mConsumer->setConsumerName(String8{"MediaCodec.release"});
+ }
+
+ const sp<Surface> &getSurface() {
+ return mSurface;
+ }
+
+private:
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ sp<Surface> mSurface;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
namespace {
enum {
@@ -1432,7 +1468,13 @@
status_t MediaCodec::release() {
sp<AMessage> msg = new AMessage(kWhatRelease, this);
+ sp<AMessage> response;
+ return PostAndAwaitResponse(msg, &response);
+}
+status_t MediaCodec::releaseAsync() {
+ sp<AMessage> msg = new AMessage(kWhatRelease, this);
+ msg->setInt32("async", 1);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
@@ -2600,7 +2642,9 @@
mResourceManagerProxy->removeClient();
- (new AMessage)->postReply(mReplyID);
+ if (mReplyID != nullptr) {
+ (new AMessage)->postReply(mReplyID);
+ }
break;
}
@@ -2987,6 +3031,26 @@
break;
}
+ int32_t async = 0;
+ if (msg->findInt32("async", &async) && async) {
+ if ((mState == CONFIGURED || mState == STARTED || mState == FLUSHED)
+ && mSurface != NULL) {
+ if (!mReleaseSurface) {
+ mReleaseSurface.reset(new ReleaseSurface);
+ }
+ status_t err = connectToSurface(mReleaseSurface->getSurface());
+ ALOGW_IF(err != OK, "error connecting to release surface: err = %d", err);
+ if (err == OK && !(mFlags & kFlagUsesSoftwareRenderer)) {
+ err = mCodec->setSurface(mReleaseSurface->getSurface());
+ ALOGW_IF(err != OK, "error setting release surface: err = %d", err);
+ }
+ if (err == OK) {
+ (void)disconnectFromSurface();
+ mSurface = mReleaseSurface->getSurface();
+ }
+ }
+ }
+
mReplyID = replyID;
setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
@@ -2999,6 +3063,12 @@
pushBlankBuffersToNativeWindow(mSurface.get());
}
+ if (async) {
+ mResourceManagerProxy->markClientForPendingRemoval();
+ (new AMessage)->postReply(mReplyID);
+ mReplyID = 0;
+ }
+
break;
}
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 022c48e..63a9dad 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -139,6 +139,8 @@
// object.
status_t release();
+ status_t releaseAsync();
+
status_t flush();
status_t queueInputBuffer(
@@ -509,6 +511,9 @@
// when low latency is on
int64_t mInputBufferCounter; // number of input buffers queued since last reset/flush
+ class ReleaseSurface;
+ std::unique_ptr<ReleaseSurface> mReleaseSurface;
+
sp<BatteryChecker> mBatteryChecker;
void statsBufferSent(int64_t presentationUs);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 6afbd4f..20f561e 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -88,6 +88,8 @@
#include "SpdifStreamOut.h"
#include "AudioHwDevice.h"
#include "NBAIO_Tee.h"
+#include "ThreadMetrics.h"
+#include "TrackMetrics.h"
#include <powermanager/IPowerManager.h>
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 1ff03c4..d8eebf3 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -171,6 +171,16 @@
void setTeePatches(TeePatches teePatches);
+ void tallyUnderrunFrames(size_t frames) override {
+ if (isOut()) { // we expect this from output tracks only
+ mAudioTrackServerProxy->tallyUnderrunFrames(frames);
+ // Fetch absolute numbers from AudioTrackShared as it counts
+ // contiguous underruns as a one -- we want a consistent number.
+ // TODO: isolate this counting into a class.
+ mTrackMetrics.logUnderruns(mAudioTrackServerProxy->getUnderrunCount(),
+ mAudioTrackServerProxy->getUnderrunFrames());
+ }
+ }
protected:
// for numerous
friend class PlaybackThread;
diff --git a/services/audioflinger/ThreadMetrics.h b/services/audioflinger/ThreadMetrics.h
new file mode 100644
index 0000000..7989de1
--- /dev/null
+++ b/services/audioflinger/ThreadMetrics.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_AUDIO_THREADMETRICS_H
+#define ANDROID_AUDIO_THREADMETRICS_H
+
+#include <mutex>
+
+namespace android {
+
+/**
+ * ThreadMetrics handles the AudioFlinger thread log statistics.
+ *
+ * We aggregate metrics for a particular device for proper analysis.
+ * This includes power, performance, and usage metrics.
+ *
+ * This class is thread-safe with a lock for safety. There is no risk of deadlock
+ * as this class only executes external one-way calls in Mediametrics and does not
+ * call any other AudioFlinger class.
+ *
+ * Terminology:
+ * An AudioInterval is a contiguous playback segment.
+ * An AudioIntervalGroup is a group of continuous playback segments on the same device.
+ *
+ * We currently deliver metrics based on an AudioIntervalGroup.
+ */
+class ThreadMetrics final {
+public:
+ ThreadMetrics(std::string metricsId, bool isOut)
+ : mMetricsId(std::move(metricsId))
+ , mIsOut(isOut)
+ {}
+
+ ~ThreadMetrics() {
+ logEndInterval(); // close any open interval groups
+ std::lock_guard l(mLock);
+ deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
+ .record();
+ }
+
+ // Called under the following circumstances
+ // 1) Upon a createPatch and we are not in standby
+ // 2) We come out of standby
+ void logBeginInterval() {
+ std::lock_guard l(mLock);
+ if (mDevices != mCreatePatchDevices) {
+ deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+ mDevices = mCreatePatchDevices; // set after endAudioIntervalGroup
+ resetIntervalGroupMetrics();
+ deliverDeviceMetrics(
+ AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, mDevices.c_str());
+ }
+ if (mIntervalStartTimeNs == 0) {
+ ++mIntervalCount;
+ mIntervalStartTimeNs = systemTime();
+ }
+ }
+
+ void logConstructor(pid_t pid, const char *threadType, int32_t id) const {
+ mediametrics::LogItem(mMetricsId)
+ .setPid(pid)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+ .set(AMEDIAMETRICS_PROP_TYPE, threadType)
+ .set(AMEDIAMETRICS_PROP_THREADID, id)
+ .record();
+ }
+
+ void logCreatePatch(const std::string& devices) {
+ std::lock_guard l(mLock);
+ mCreatePatchDevices = devices;
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
+ .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, devices)
+ .record();
+ }
+
+ // Called when we are removed from the Thread.
+ void logEndInterval() {
+ std::lock_guard l(mLock);
+ if (mIntervalStartTimeNs != 0) {
+ const int64_t elapsedTimeNs = systemTime() - mIntervalStartTimeNs;
+ mIntervalStartTimeNs = 0;
+ mCumulativeTimeNs += elapsedTimeNs;
+ mDeviceTimeNs += elapsedTimeNs;
+ }
+ }
+
+ void logThrottleMs(double throttleMs) const {
+ mediametrics::LogItem(mMetricsId)
+ // ms units always double
+ .set(AMEDIAMETRICS_PROP_THROTTLEMS, (double)throttleMs)
+ .record();
+ }
+
+ void logLatency(double latencyMs) {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
+ .record();
+ std::lock_guard l(mLock);
+ mDeviceLatencyMs.add(latencyMs);
+ }
+
+ // TODO: further implement this.
+ void logUnderrunFrames(size_t count, size_t frames) {
+ std::lock_guard l(mLock);
+ mUnderrunCount = count;
+ mUnderrunFrames = frames;
+ }
+
+ const std::string& getMetricsId() const {
+ return mMetricsId;
+ }
+
+private:
+ // no lock required - all arguments and constants.
+ void deliverDeviceMetrics(const char *eventName, const char *devices) const {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+ .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
+ : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
+ .record();
+ }
+
+ void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
+ if (mIntervalCount > 0) {
+ mediametrics::LogItem item(mMetricsId);
+ item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
+ .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
+ .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+ .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
+ if (mDeviceLatencyMs.getN() > 0) {
+ item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean());
+ }
+ if (mUnderrunCount > 0) {
+ item.set(AMEDIAMETRICS_PROP_UNDERRUN, (int32_t)mUnderrunCount)
+ .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES, (int64_t)mUnderrunFrames);
+ }
+ item.record();
+ }
+ }
+
+ void resetIntervalGroupMetrics() REQUIRES(mLock) {
+ // mDevices is not reset by clear
+
+ mIntervalCount = 0;
+ mIntervalStartTimeNs = 0;
+ // mCumulativeTimeNs is not reset by clear.
+ mDeviceTimeNs = 0;
+
+ mDeviceLatencyMs.reset();
+
+ mUnderrunCount = 0;
+ mUnderrunFrames = 0;
+ }
+
+ const std::string mMetricsId;
+ const bool mIsOut; // if true, than a playback track, otherwise used for record.
+
+ mutable std::mutex mLock;
+
+ // Devices in the interval group.
+ std::string mDevices GUARDED_BY(mLock);
+ std::string mCreatePatchDevices GUARDED_BY(mLock);
+
+ // Number of intervals and playing time
+ int32_t mIntervalCount GUARDED_BY(mLock) = 0;
+ int64_t mIntervalStartTimeNs GUARDED_BY(mLock) = 0;
+ int64_t mCumulativeTimeNs GUARDED_BY(mLock) = 0;
+ int64_t mDeviceTimeNs GUARDED_BY(mLock) = 0;
+
+ // latency and startup for each interval.
+ audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
+
+ // underrun count and frames
+ int64_t mUnderrunCount GUARDED_BY(mLock) = 0;
+ int64_t mUnderrunFrames GUARDED_BY(mLock) = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_THREADMETRICS_H
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 5d9c35a..594baf8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -220,6 +220,9 @@
{
std::stringstream ss;
for (size_t i = 0; i < patch->num_sinks; ++i) {
+ if (i > 0) {
+ ss << "|";
+ }
ss << "(" << toString(patch->sinks[i].ext.device.type)
<< ", " << patch->sinks[i].ext.device.address << ")";
}
@@ -230,6 +233,9 @@
{
std::stringstream ss;
for (size_t i = 0; i < patch->num_sources; ++i) {
+ if (i > 0) {
+ ss << "|";
+ }
ss << "(" << toString(patch->sources[i].ext.device.type)
<< ", " << patch->sources[i].ext.device.address << ")";
}
@@ -486,11 +492,13 @@
}
AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- type_t type, bool systemReady)
+ type_t type, bool systemReady, bool isOut)
: Thread(false /*canCallJava*/),
mType(type),
mAudioFlinger(audioFlinger),
- mMetricsId(std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(id)),
+ mThreadMetrics(std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(id),
+ isOut),
+ mIsOut(isOut),
// mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
// are set by PlaybackThread::readOutputParameters_l() or
// RecordThread::readInputParameters_l()
@@ -502,13 +510,7 @@
mSystemReady(systemReady),
mSignalPending(false)
{
- mediametrics::LogItem(mMetricsId)
- .setPid(getpid())
- .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
- .set(AMEDIAMETRICS_PROP_TYPE, threadTypeToString(type))
- .set(AMEDIAMETRICS_PROP_THREADID, id)
- .record();
-
+ mThreadMetrics.logConstructor(getpid(), threadTypeToString(type), id);
memset(&mPatch, 0, sizeof(struct audio_patch));
}
@@ -525,10 +527,6 @@
}
sendStatistics(true /* force */);
-
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR)
- .record();
}
status_t AudioFlinger::ThreadBase::readyToRun()
@@ -1686,6 +1684,7 @@
#ifdef TEE_SINK
track->dumpTee(-1 /* fd */, "_REMOVE");
#endif
+ track->logEndInterval(); // log to MediaMetrics
return index;
}
@@ -1828,7 +1827,7 @@
audio_io_handle_t id,
type_t type,
bool systemReady)
- : ThreadBase(audioFlinger, id, type, systemReady),
+ : ThreadBase(audioFlinger, id, type, systemReady, true /* isOut */),
mNormalFrameCount(0), mSinkBuffer(NULL),
mMixerBufferEnabled(AudioFlinger::kEnableExtendedPrecision),
mMixerBuffer(NULL),
@@ -2553,6 +2552,7 @@
chain->incActiveTrackCnt();
}
+ track->logBeginInterval(patchSinksToString(&mPatch)); // log to MediaMetrics
status = NO_ERROR;
}
@@ -2876,7 +2876,7 @@
}
audio_output_flags_t flags = mOutput->flags;
- mediametrics::LogItem item(mMetricsId);
+ mediametrics::LogItem item(mThreadMetrics.getMetricsId()); // TODO: method in ThreadMetrics?
item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
.set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
.set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
@@ -3134,7 +3134,10 @@
mNumWrites++;
mInWrite = false;
- mStandby = false;
+ if (mStandby) {
+ mThreadMetrics.logBeginInterval();
+ mStandby = false;
+ }
return bytesWritten;
}
@@ -3673,8 +3676,9 @@
// This is where we go into standby
if (!mStandby) {
LOG_AUDIO_STATE();
+ mThreadMetrics.logEndInterval();
+ mStandby = true;
}
- mStandby = true;
sendStatistics(false /* force */);
}
@@ -3978,10 +3982,7 @@
const int32_t throttleMs = (int32_t)mHalfBufferMs - deltaMs;
if ((signed)mHalfBufferMs >= throttleMs && throttleMs > 0) {
- mediametrics::LogItem(mMetricsId)
- // ms units always double
- .set(AMEDIAMETRICS_PROP_THROTTLEMS, (double)throttleMs)
- .record();
+ mThreadMetrics.logThrottleMs((double)throttleMs);
usleep(throttleMs * 1000);
// notify of throttle start on verbose log
@@ -4256,10 +4257,16 @@
status = mOutput->stream->setParameters(param.toString());
*handle = AUDIO_PATCH_HANDLE_NONE;
}
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
- .set(AMEDIAMETRICS_PROP_OUTPUTDEVICES, patchSinksToString(patch).c_str())
- .record();
+ const std::string patchSinksAsString = patchSinksToString(patch);
+
+ mThreadMetrics.logEndInterval();
+ mThreadMetrics.logCreatePatch(patchSinksAsString);
+ mThreadMetrics.logBeginInterval();
+ // also dispatch to active AudioTracks for MediaMetrics
+ for (const auto &track : mActiveTracks) {
+ track->logEndInterval();
+ track->logBeginInterval(patchSinksAsString);
+ }
if (configChanged) {
sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
@@ -4802,9 +4809,8 @@
// DeferredOperations handles statistics after setting mixerStatus.
class DeferredOperations {
public:
- DeferredOperations(mixer_state *mixerStatus, const std::string &metricsId)
- : mMixerStatus(mixerStatus)
- , mMetricsId(metricsId) {}
+ explicit DeferredOperations(mixer_state *mixerStatus)
+ : mMixerStatus(mixerStatus) {}
// when leaving scope, tally frames properly.
~DeferredOperations() {
@@ -4812,19 +4818,9 @@
// because that is when the underrun occurs.
// We do not distinguish between FastTracks and NormalTracks here.
if (*mMixerStatus == MIXER_TRACKS_READY && mUnderrunFrames.size() > 0) {
- mediametrics::LogItem item(mMetricsId);
-
- item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN);
for (const auto &underrun : mUnderrunFrames) {
- underrun.first->mAudioTrackServerProxy->tallyUnderrunFrames(
- underrun.second);
-
- item.set(std::string("[" AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK)
- + std::to_string(underrun.first->portId())
- + "]" AMEDIAMETRICS_PROP_UNDERRUN,
- (int32_t)underrun.second);
+ underrun.first->tallyUnderrunFrames(underrun.second);
}
- item.record();
}
}
@@ -4837,9 +4833,8 @@
private:
const mixer_state * const mMixerStatus;
- const std::string& mMetricsId;
std::vector<std::pair<sp<Track>, size_t>> mUnderrunFrames;
- } deferredOperations(&mixerStatus, mMetricsId);
+ } deferredOperations(&mixerStatus);
// implicit nested scope for variable capture
bool noFastHapticTrack = true;
@@ -5578,7 +5573,10 @@
status = mOutput->stream->setParameters(keyValuePair);
if (!mStandby && status == INVALID_OPERATION) {
mOutput->standby();
- mStandby = true;
+ if (!mStandby) {
+ mThreadMetrics.logEndInterval();
+ mStandby = true;
+ }
mBytesWritten = 0;
status = mOutput->stream->setParameters(keyValuePair);
}
@@ -6091,7 +6089,10 @@
status = mOutput->stream->setParameters(keyValuePair);
if (!mStandby && status == INVALID_OPERATION) {
mOutput->standby();
- mStandby = true;
+ if (!mStandby) {
+ mThreadMetrics.logEndInterval();
+ mStandby = true;
+ }
mBytesWritten = 0;
status = mOutput->stream->setParameters(keyValuePair);
}
@@ -6686,7 +6687,10 @@
// TODO: Report correction for the other output tracks and show in the dump.
}
- mStandby = false;
+ if (mStandby) {
+ mThreadMetrics.logBeginInterval();
+ mStandby = false;
+ }
return (ssize_t)mSinkBufferSize;
}
@@ -6848,7 +6852,7 @@
audio_io_handle_t id,
bool systemReady
) :
- ThreadBase(audioFlinger, id, RECORD, systemReady),
+ ThreadBase(audioFlinger, id, RECORD, systemReady, false /* isOut */),
mInput(input),
mSource(mInput),
mActiveTracks(&this->mLocalLog),
@@ -7136,7 +7140,10 @@
case TrackBase::STARTING_2:
doBroadcast = true;
- mStandby = false;
+ if (mStandby) {
+ mThreadMetrics.logBeginInterval();
+ mStandby = false;
+ }
activeTrack->mState = TrackBase::ACTIVE;
allStopped = false;
break;
@@ -7577,6 +7584,7 @@
{
if (!mStandby) {
inputStandBy();
+ mThreadMetrics.logEndInterval();
mStandby = true;
}
}
@@ -7881,6 +7889,9 @@
sendIoConfigEvent_l(
AUDIO_CLIENT_STARTED, recordTrack->creatorPid(), recordTrack->portId());
}
+
+ recordTrack->logBeginInterval(patchSourcesToString(&mPatch)); // log to MediaMetrics
+
// Catch up with current buffer indices if thread is already running.
// This is what makes a new client discard all buffered data. If the track's mRsmpInFront
// was initialized to some value closer to the thread's mRsmpInFront, then the track could
@@ -8545,12 +8556,15 @@
mPatch = *patch;
}
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATEAUDIOPATCH)
- .set(AMEDIAMETRICS_PROP_INPUTDEVICES, patchSourcesToString(patch).c_str())
- .set(AMEDIAMETRICS_PROP_SOURCE, toString(mAudioSource).c_str())
- .record();
-
+ const std::string pathSourcesAsString = patchSourcesToString(patch);
+ mThreadMetrics.logEndInterval();
+ mThreadMetrics.logCreatePatch(pathSourcesAsString);
+ mThreadMetrics.logBeginInterval();
+ // also dispatch to active AudioRecords
+ for (const auto &track : mActiveTracks) {
+ track->logEndInterval();
+ track->logBeginInterval(pathSourcesAsString);
+ }
return status;
}
@@ -8657,8 +8671,8 @@
AudioFlinger::MmapThread::MmapThread(
const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady)
- : ThreadBase(audioFlinger, id, MMAP, systemReady),
+ AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady, bool isOut)
+ : ThreadBase(audioFlinger, id, MMAP, systemReady, isOut),
mSessionId(AUDIO_SESSION_NONE),
mPortId(AUDIO_PORT_HANDLE_NONE),
mHalStream(stream), mHalDevice(hwDev->hwDevice()), mAudioHwDev(hwDev),
@@ -8741,7 +8755,10 @@
ALOGE("%s: error mHalStream->start() = %d for first track", __FUNCTION__, ret);
return ret;
}
- mStandby = false;
+ if (mStandby) {
+ mThreadMetrics.logBeginInterval();
+ mStandby = false;
+ }
return NO_ERROR;
}
@@ -8861,6 +8878,7 @@
chain->incActiveTrackCnt();
}
+ track->logBeginInterval(patchSinksToString(&mPatch)); // log to MediaMetrics
*handle = portId;
broadcast_l();
@@ -8929,7 +8947,10 @@
return INVALID_OPERATION;
}
mHalStream->standby();
- mStandby = true;
+ if (!mStandby) {
+ mThreadMetrics.logEndInterval();
+ mStandby = true;
+ }
releaseWakeLock();
return NO_ERROR;
}
@@ -8946,6 +8967,27 @@
result = mHalStream->getBufferSize(&mBufferSize);
LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving buffer size from HAL: %d", result);
mFrameCount = mBufferSize / mFrameSize;
+
+ // TODO: make a readHalParameters call?
+ mediametrics::LogItem item(mThreadMetrics.getMetricsId());
+ item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_READPARAMETERS)
+ .set(AMEDIAMETRICS_PROP_ENCODING, formatToString(mFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_SAMPLERATE, (int32_t)mSampleRate)
+ .set(AMEDIAMETRICS_PROP_CHANNELMASK, (int32_t)mChannelMask)
+ .set(AMEDIAMETRICS_PROP_CHANNELCOUNT, (int32_t)mChannelCount)
+ .set(AMEDIAMETRICS_PROP_FRAMECOUNT, (int32_t)mFrameCount)
+ /*
+ .set(AMEDIAMETRICS_PROP_FLAGS, toString(flags).c_str())
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAPTIC AMEDIAMETRICS_PROP_CHANNELMASK,
+ (int32_t)mHapticChannelMask)
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAPTIC AMEDIAMETRICS_PROP_CHANNELCOUNT,
+ (int32_t)mHapticChannelCount)
+ */
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_ENCODING,
+ formatToString(mHALFormat).c_str())
+ .set(AMEDIAMETRICS_PROP_PREFIX_HAL AMEDIAMETRICS_PROP_FRAMECOUNT,
+ (int32_t)mFrameCount) // sic - added HAL
+ .record();
}
bool AudioFlinger::MmapThread::threadLoop()
@@ -9357,7 +9399,7 @@
AudioFlinger::MmapPlaybackThread::MmapPlaybackThread(
const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
AudioHwDevice *hwDev, AudioStreamOut *output, bool systemReady)
- : MmapThread(audioFlinger, id, hwDev, output->stream, systemReady),
+ : MmapThread(audioFlinger, id, hwDev, output->stream, systemReady, true /* isOut */),
mStreamType(AUDIO_STREAM_MUSIC),
mStreamVolume(1.0),
mStreamMute(false),
@@ -9568,7 +9610,7 @@
AudioFlinger::MmapCaptureThread::MmapCaptureThread(
const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
AudioHwDevice *hwDev, AudioStreamIn *input, bool systemReady)
- : MmapThread(audioFlinger, id, hwDev, input->stream, systemReady),
+ : MmapThread(audioFlinger, id, hwDev, input->stream, systemReady, false /* isOut */),
mInput(input)
{
snprintf(mThreadName, kThreadNameLength, "AudioMmapIn_%X", id);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index e5a6196..5b8c081 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -37,7 +37,7 @@
static const char *threadTypeToString(type_t type);
ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- type_t type, bool systemReady);
+ type_t type, bool systemReady, bool isOut);
virtual ~ThreadBase();
virtual status_t readyToRun();
@@ -330,7 +330,7 @@
return mInDeviceTypeAddr;
}
- virtual bool isOutput() const = 0;
+ bool isOutput() const { return mIsOut; }
virtual sp<StreamHalInterface> stream() const = 0;
@@ -524,7 +524,8 @@
Condition mWaitWorkCV;
const sp<AudioFlinger> mAudioFlinger;
- const std::string mMetricsId;
+ ThreadMetrics mThreadMetrics;
+ const bool mIsOut;
// updated by PlaybackThread::readOutputParameters_l() or
// RecordThread::readInputParameters_l()
@@ -911,9 +912,6 @@
// Return the asynchronous signal wait time.
virtual int64_t computeWaitTimeNs_l() const { return INT64_MAX; }
-
- virtual bool isOutput() const override { return true; }
-
// returns true if the track is allowed to be added to the thread.
virtual bool isTrackAllowed_l(
audio_channel_mask_t channelMask __unused,
@@ -1651,7 +1649,6 @@
ThreadBase::acquireWakeLock_l();
mActiveTracks.updatePowerState(this, true /* force */);
}
- virtual bool isOutput() const override { return false; }
void checkBtNrec();
@@ -1760,7 +1757,8 @@
#include "MmapTracks.h"
MmapThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady);
+ AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady,
+ bool isOut);
virtual ~MmapThread();
virtual void configure(const audio_attributes_t *attr,
@@ -1888,8 +1886,6 @@
virtual void checkSilentMode_l();
void processVolume_l() override;
- virtual bool isOutput() const override { return true; }
-
void updateMetadata_l() override;
virtual void toAudioPortConfig(struct audio_port_config *config);
@@ -1916,7 +1912,6 @@
AudioStreamIn* clearInput();
status_t exitStandby() override;
- virtual bool isOutput() const override { return false; }
void updateMetadata_l() override;
void processVolume_l() override;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index e39b944..15c66fb 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -97,10 +97,7 @@
virtual void invalidate() {
if (mIsInvalid) return;
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_EVENT,
- AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
- .record();
+ mTrackMetrics.logInvalidate();
mIsInvalid = true;
}
bool isInvalid() const { return mIsInvalid; }
@@ -242,6 +239,20 @@
}
}
+ // Called by the PlaybackThread to indicate that the track is becoming active
+ // and a new interval should start with a given device list.
+ void logBeginInterval(const std::string& devices) {
+ mTrackMetrics.logBeginInterval(devices);
+ }
+
+ // Called by the PlaybackThread to indicate the track is no longer active.
+ void logEndInterval() {
+ mTrackMetrics.logEndInterval();
+ }
+
+ // Called to tally underrun frames in playback.
+ virtual void tallyUnderrunFrames(size_t /* frames */) {}
+
protected:
DISALLOW_COPY_AND_ASSIGN(TrackBase);
@@ -367,7 +378,7 @@
int64_t mLogStartTimeNs = 0;
int64_t mLogStartFrames = 0;
- const std::string mMetricsId;
+ TrackMetrics mTrackMetrics;
bool mServerLatencySupported = false;
std::atomic<bool> mServerLatencyFromTrack{}; // latency from track or server timestamp.
diff --git a/services/audioflinger/TrackMetrics.h b/services/audioflinger/TrackMetrics.h
new file mode 100644
index 0000000..399c788
--- /dev/null
+++ b/services/audioflinger/TrackMetrics.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#ifndef ANDROID_AUDIO_TRACKMETRICS_H
+#define ANDROID_AUDIO_TRACKMETRICS_H
+
+#include <mutex>
+
+namespace android {
+
+/**
+ * TrackMetrics handles the AudioFlinger track metrics.
+ *
+ * We aggregate metrics for a particular device for proper analysis.
+ * This includes power, performance, and usage metrics.
+ *
+ * This class is thread-safe with a lock for safety. There is no risk of deadlock
+ * as this class only executes external one-way calls in Mediametrics and does not
+ * call any other AudioFlinger class.
+ *
+ * Terminology:
+ * An AudioInterval is a contiguous playback segment.
+ * An AudioIntervalGroup is a group of continuous playback segments on the same device.
+ *
+ * We currently deliver metrics based on an AudioIntervalGroup.
+ */
+class TrackMetrics final {
+public:
+ TrackMetrics(std::string metricsId, bool isOut)
+ : mMetricsId(std::move(metricsId))
+ , mIsOut(isOut)
+ {} // we don't log a constructor item, we wait for more info in logConstructor().
+
+ ~TrackMetrics() {
+ logEndInterval();
+ std::lock_guard l(mLock);
+ deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+ // we don't log a destructor item here.
+ }
+
+ // Called under the following circumstances
+ // 1) when we are added to the Thread
+ // 2) when we have a createPatch in the Thread.
+ void logBeginInterval(const std::string& devices) {
+ std::lock_guard l(mLock);
+ if (mDevices != devices) {
+ deliverCumulativeMetrics(AMEDIAMETRICS_PROP_EVENT_VALUE_ENDAUDIOINTERVALGROUP);
+ mDevices = devices;
+ resetIntervalGroupMetrics();
+ deliverDeviceMetrics(
+ AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, devices.c_str());
+ }
+ ++mIntervalCount;
+ mIntervalStartTimeNs = systemTime();
+ }
+
+ void logConstructor(pid_t creatorPid, uid_t creatorUid) const {
+ // Once this item is logged by the server, the client can add properties.
+ // no lock required, all local or const variables.
+ mediametrics::LogItem(mMetricsId)
+ .setPid(creatorPid)
+ .setUid(creatorUid)
+ .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)creatorUid)
+ .set(AMEDIAMETRICS_PROP_EVENT,
+ AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
+ .record();
+ }
+
+ // Called when we are removed from the Thread.
+ void logEndInterval() {
+ std::lock_guard l(mLock);
+ if (mIntervalStartTimeNs != 0) {
+ const int64_t elapsedTimeNs = systemTime() - mIntervalStartTimeNs;
+ mIntervalStartTimeNs = 0;
+ mCumulativeTimeNs += elapsedTimeNs;
+ mDeviceTimeNs += elapsedTimeNs;
+ }
+ }
+
+ void logInvalidate() const {
+ // no lock required, all local or const variables.
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT,
+ AMEDIAMETRICS_PROP_EVENT_VALUE_INVALIDATE)
+ .record();
+ }
+
+ void logLatencyAndStartup(double latencyMs, double startupMs) {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
+ .set(AMEDIAMETRICS_PROP_STARTUPMS, startupMs)
+ .record();
+ std::lock_guard l(mLock);
+ mDeviceLatencyMs.add(latencyMs);
+ mDeviceStartupMs.add(startupMs);
+ }
+
+ // may be called multiple times during an interval
+ void logVolume(float volume) {
+ const int64_t timeNs = systemTime();
+ std::lock_guard l(mLock);
+ if (mStartVolumeTimeNs == 0) {
+ mDeviceVolume = mVolume = volume;
+ mLastVolumeChangeTimeNs = mStartVolumeTimeNs = timeNs;
+ return;
+ }
+ mDeviceVolume = (mDeviceVolume * (mLastVolumeChangeTimeNs - mStartVolumeTimeNs) +
+ mVolume * (timeNs - mLastVolumeChangeTimeNs)) / (timeNs - mStartVolumeTimeNs);
+ mVolume = volume;
+ mLastVolumeChangeTimeNs = timeNs;
+ }
+
+ // Use absolute numbers returned by AudioTrackShared.
+ void logUnderruns(size_t count, size_t frames) {
+ std::lock_guard l(mLock);
+ mUnderrunCount = count;
+ mUnderrunFrames = frames;
+ // Consider delivering a message here (also be aware of excessive spam).
+ }
+
+private:
+ // no lock required - all arguments and constants.
+ void deliverDeviceMetrics(const char *eventName, const char *devices) const {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+ .set(mIsOut ? AMEDIAMETRICS_PROP_OUTPUTDEVICES
+ : AMEDIAMETRICS_PROP_INPUTDEVICES, devices)
+ .record();
+ }
+
+ void deliverCumulativeMetrics(const char *eventName) const REQUIRES(mLock) {
+ if (mIntervalCount > 0) {
+ mediametrics::LogItem item(mMetricsId);
+ item.set(AMEDIAMETRICS_PROP_CUMULATIVETIMENS, mCumulativeTimeNs)
+ .set(AMEDIAMETRICS_PROP_DEVICETIMENS, mDeviceTimeNs)
+ .set(AMEDIAMETRICS_PROP_EVENT, eventName)
+ .set(AMEDIAMETRICS_PROP_INTERVALCOUNT, (int32_t)mIntervalCount);
+ if (mIsOut) {
+ item.set(AMEDIAMETRICS_PROP_DEVICEVOLUME, mDeviceVolume);
+ }
+ if (mDeviceLatencyMs.getN() > 0) {
+ item.set(AMEDIAMETRICS_PROP_DEVICELATENCYMS, mDeviceLatencyMs.getMean())
+ .set(AMEDIAMETRICS_PROP_DEVICESTARTUPMS, mDeviceStartupMs.getMean());
+ }
+ if (mUnderrunCount > 0) {
+ item.set(AMEDIAMETRICS_PROP_UNDERRUN,
+ (int32_t)(mUnderrunCount - mUnderrunCountSinceIntervalGroup))
+ .set(AMEDIAMETRICS_PROP_UNDERRUNFRAMES,
+ (int64_t)(mUnderrunFrames - mUnderrunFramesSinceIntervalGroup));
+ }
+ item.record();
+ }
+ }
+
+ void resetIntervalGroupMetrics() REQUIRES(mLock) {
+ // mDevices is not reset by resetIntervalGroupMetrics.
+
+ mIntervalCount = 0;
+ mIntervalStartTimeNs = 0;
+ // mCumulativeTimeNs is not reset by resetIntervalGroupMetrics.
+ mDeviceTimeNs = 0;
+
+ mVolume = 0.f;
+ mDeviceVolume = 0.f;
+ mStartVolumeTimeNs = 0;
+ mLastVolumeChangeTimeNs = 0;
+
+ mDeviceLatencyMs.reset();
+ mDeviceStartupMs.reset();
+
+ mUnderrunCountSinceIntervalGroup = mUnderrunCount;
+ mUnderrunFramesSinceIntervalGroup = mUnderrunFrames;
+ // do not reset mUnderrunCount - it keeps continuously running for tracks.
+ }
+
+ const std::string mMetricsId;
+ const bool mIsOut; // if true, than a playback track, otherwise used for record.
+
+ mutable std::mutex mLock;
+
+ // Devices in the interval group.
+ std::string mDevices GUARDED_BY(mLock);
+
+ // Number of intervals and playing time
+ int32_t mIntervalCount GUARDED_BY(mLock) = 0;
+ int64_t mIntervalStartTimeNs GUARDED_BY(mLock) = 0;
+ int64_t mCumulativeTimeNs GUARDED_BY(mLock) = 0;
+ int64_t mDeviceTimeNs GUARDED_BY(mLock) = 0;
+
+ // Average volume
+ double mVolume GUARDED_BY(mLock) = 0.f;
+ double mDeviceVolume GUARDED_BY(mLock) = 0.f;
+ int64_t mStartVolumeTimeNs GUARDED_BY(mLock) = 0;
+ int64_t mLastVolumeChangeTimeNs GUARDED_BY(mLock) = 0;
+
+ // latency and startup for each interval.
+ audio_utils::Statistics<double> mDeviceLatencyMs GUARDED_BY(mLock);
+ audio_utils::Statistics<double> mDeviceStartupMs GUARDED_BY(mLock);
+
+ // underrun count and frames
+ int64_t mUnderrunCount GUARDED_BY(mLock) = 0;
+ int64_t mUnderrunFrames GUARDED_BY(mLock) = 0;
+ int64_t mUnderrunCountSinceIntervalGroup GUARDED_BY(mLock) = 0;
+ int64_t mUnderrunFramesSinceIntervalGroup GUARDED_BY(mLock) = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_AUDIO_TRACKMETRICS_H
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 4898d37..58c61c9 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -106,7 +106,7 @@
mThreadIoHandle(thread ? thread->id() : AUDIO_IO_HANDLE_NONE),
mPortId(portId),
mIsInvalid(false),
- mMetricsId(std::move(metricsId)),
+ mTrackMetrics(std::move(metricsId), isOut),
mCreatorPid(creatorPid)
{
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -602,13 +602,7 @@
}
// Once this item is logged by the server, the client can add properties.
- mediametrics::LogItem(mMetricsId)
- .setPid(creatorPid)
- .setUid(uid)
- .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)uid)
- .set(AMEDIAMETRICS_PROP_EVENT,
- AMEDIAMETRICS_PROP_PREFIX_SERVER AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
- .record();
+ mTrackMetrics.logConstructor(creatorPid, uid);
}
AudioFlinger::PlaybackThread::Track::~Track()
@@ -1249,6 +1243,7 @@
if (mFinalVolume != volume) { // Compare to an epsilon if too many meaningless updates
mFinalVolume = volume;
setMetadataHasChanged();
+ mTrackMetrics.logVolume(volume);
}
}
@@ -1534,10 +1529,7 @@
(long long)mLogStartTimeNs,
(long long)local.mPosition[ExtendedTimestamp::LOCATION_SERVER],
(long long)mLogStartFrames);
- mediametrics::LogItem(mMetricsId)
- .set(AMEDIAMETRICS_PROP_LATENCYMS, latencyMs)
- .set(AMEDIAMETRICS_PROP_STARTUPMS, startUpMs)
- .record();
+ mTrackMetrics.logLatencyAndStartup(latencyMs, startUpMs);
}
}
}
@@ -2163,12 +2155,7 @@
#endif
// Once this item is logged by the server, the client can add properties.
- mediametrics::LogItem(mMetricsId)
- .setPid(creatorPid)
- .setUid(uid)
- .set(AMEDIAMETRICS_PROP_ALLOWUID, (int32_t)uid)
- .set(AMEDIAMETRICS_PROP_EVENT, "server." AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR)
- .record();
+ mTrackMetrics.logConstructor(creatorPid, uid);
}
AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
@@ -2725,9 +2712,12 @@
nullptr /* buffer */, (size_t)0 /* bufferSize */,
sessionId, creatorPid, uid, isOut,
ALLOC_NONE,
- TYPE_DEFAULT, portId),
+ TYPE_DEFAULT, portId,
+ std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP) + std::to_string(portId)),
mPid(pid), mSilenced(false), mSilencedNotified(false)
{
+ // Once this item is logged by the server, the client can add properties.
+ mTrackMetrics.logConstructor(creatorPid, uid);
}
AudioFlinger::MmapThread::MmapTrack::~MmapTrack()
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 13e2093..bcf6f38 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -954,7 +954,8 @@
primaryMix->mDeviceAddress,
AUDIO_FORMAT_DEFAULT);
sp<SwAudioOutputDescriptor> policyDesc = primaryMix->getOutput();
- if (policyDesc == nullptr || (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+ if (deviceDesc != nullptr
+ && (policyDesc == nullptr || (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT))) {
audio_io_handle_t newOutput;
status = openDirectOutput(
*stream, session, config,
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index d743be9..a15970a 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -676,6 +676,7 @@
case AUDIO_SOURCE_VOICE_CALL:
case AUDIO_SOURCE_REMOTE_SUBMIX:
case AUDIO_SOURCE_FM_TUNER:
+ case AUDIO_SOURCE_ECHO_REFERENCE:
return true;
default:
break;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 2d46122..b00a2d9 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2344,6 +2344,21 @@
}
}
+bool Camera3Device::checkAbandonedStreamsLocked() {
+ if ((mInputStream.get() != nullptr) && (mInputStream->isAbandoned())) {
+ return true;
+ }
+
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ auto stream = mOutputStreams[i];
+ if ((stream.get() != nullptr) && (stream->isAbandoned())) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool Camera3Device::reconfigureCamera(const CameraMetadata& sessionParams) {
ATRACE_CALL();
bool ret = false;
@@ -2352,6 +2367,12 @@
nsecs_t maxExpectedDuration = getExpectedInFlightDuration();
Mutex::Autolock l(mLock);
+ if (checkAbandonedStreamsLocked()) {
+ ALOGW("%s: Abandoned stream detected, session parameters can't be applied correctly!",
+ __FUNCTION__);
+ return true;
+ }
+
auto rc = internalPauseAndWaitLocked(maxExpectedDuration);
if (rc == NO_ERROR) {
mNeedConfig = true;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index b373a64..19ecf4b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -648,6 +648,12 @@
bool reconfigureCamera(const CameraMetadata& sessionParams);
/**
+ * Return true in case of any output or input abandoned streams,
+ * otherwise return false.
+ */
+ bool checkAbandonedStreamsLocked();
+
+ /**
* Filter stream session parameters and configure camera HAL.
*/
status_t filterParamsAndConfigureLocked(const CameraMetadata& sessionParams,
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 4c8366f..603f516 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -259,13 +259,15 @@
}
// Fix up some result metadata to account for HAL-level distortion correction
- status_t res =
- states.distortionMappers[states.cameraId.c_str()].correctCaptureResult(
- &captureResult.mMetadata);
- if (res != OK) {
- SET_ERR("Unable to correct capture result metadata for frame %d: %s (%d)",
- frameNumber, strerror(-res), res);
- return;
+ status_t res = OK;
+ auto iter = states.distortionMappers.find(states.cameraId.c_str());
+ if (iter != states.distortionMappers.end()) {
+ res = iter->second.correctCaptureResult(&captureResult.mMetadata);
+ if (res != OK) {
+ SET_ERR("Unable to correct capture result metadata for frame %d: %s (%d)",
+ frameNumber, strerror(-res), res);
+ return;
+ }
}
// Fix up result metadata to account for zoom ratio availabilities between
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index be5af00..ff45c87 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -114,6 +114,7 @@
info.uid = uid;
info.clientId = clientId;
info.client = client;
+ info.pendingRemoval = false;
index = infos.add(clientId, info);
}
@@ -648,6 +649,36 @@
return Status::ok();
}
+Status ResourceManagerService::markClientForPendingRemoval(int32_t pid, int64_t clientId) {
+ String8 log = String8::format(
+ "markClientForPendingRemoval(pid %d, clientId %lld)",
+ pid, (long long) clientId);
+ mServiceLog->add(log);
+
+ Mutex::Autolock lock(mLock);
+ if (!mProcessInfo->isValidPid(pid)) {
+ ALOGE("Rejected markClientForPendingRemoval call with invalid pid.");
+ return Status::fromServiceSpecificError(BAD_VALUE);
+ }
+ ssize_t index = mMap.indexOfKey(pid);
+ if (index < 0) {
+ ALOGV("markClientForPendingRemoval: didn't find pid %d for clientId %lld",
+ pid, (long long)clientId);
+ return Status::ok();
+ }
+ ResourceInfos &infos = mMap.editValueAt(index);
+
+ index = infos.indexOfKey(clientId);
+ if (index < 0) {
+ ALOGV("markClientForPendingRemoval: didn't find clientId %lld", (long long) clientId);
+ return Status::ok();
+ }
+
+ ResourceInfo &info = infos.editValueAt(index);
+ info.pendingRemoval = true;
+ return Status::ok();
+}
+
bool ResourceManagerService::getPriority_l(int pid, int* priority) {
int newPid = pid;
@@ -693,6 +724,12 @@
int lowestPriorityPid;
int lowestPriority;
int callingPriority;
+
+ // Before looking into other processes, check if we have clients marked for
+ // pending removal in the same process.
+ if (getBiggestClient_l(callingPid, type, client, true /* pendingRemovalOnly */)) {
+ return true;
+ }
if (!getPriority_l(callingPid, &callingPriority)) {
ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
callingPid);
@@ -761,7 +798,8 @@
}
bool ResourceManagerService::getBiggestClient_l(
- int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client) {
+ int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client,
+ bool pendingRemovalOnly) {
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
@@ -773,6 +811,9 @@
const ResourceInfos &infos = mMap.valueAt(index);
for (size_t i = 0; i < infos.size(); ++i) {
const ResourceList &resources = infos[i].resources;
+ if (pendingRemovalOnly && !infos[i].pendingRemoval) {
+ continue;
+ }
for (auto it = resources.begin(); it != resources.end(); it++) {
const MediaResourceParcel &resource = it->second;
if (resource.type == type) {
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index f500c62..ee982b7 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -18,6 +18,8 @@
#ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
+#include <map>
+
#include <aidl/android/media/BnResourceManagerService.h>
#include <arpa/inet.h>
#include <media/MediaResource.h>
@@ -50,6 +52,7 @@
std::shared_ptr<IResourceManagerClient> client;
sp<DeathNotifier> deathNotifier;
ResourceList resources;
+ bool pendingRemoval{false};
};
// TODO: convert these to std::map
@@ -122,6 +125,8 @@
int originalPid,
int newPid) override;
+ Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override;
+
Status removeResource(int pid, int64_t clientId, bool checkValid);
private:
@@ -146,7 +151,8 @@
// Gets the client who owns biggest piece of specified resource type from pid.
// Returns false if failed. The client will remain unchanged if failed.
bool getBiggestClient_l(int pid, MediaResource::Type type,
- std::shared_ptr<IResourceManagerClient> *client);
+ std::shared_ptr<IResourceManagerClient> *client,
+ bool pendingRemovalOnly = false);
bool isCallingPriorityHigher_l(int callingPid, int pid);
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 5d839fa..702935d 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -472,6 +472,56 @@
}
}
+ void testMarkClientForPendingRemoval() {
+ bool result;
+
+ {
+ addResource();
+ mService->mSupportsSecureWithNonSecureCodec = true;
+
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+
+ // Remove low priority clients
+ mService->removeClient(kTestPid1, getId(mTestClient1));
+
+ // no lower priority client
+ CHECK_STATUS_FALSE(mService->reclaimResource(kTestPid2, resources, &result));
+ verifyClients(false /* c1 */, false /* c2 */, false /* c3 */);
+
+ mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
+
+ // client marked for pending removal from the same process got reclaimed
+ CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+ verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+
+ // clean up client 3 which still left
+ mService->removeClient(kTestPid2, getId(mTestClient3));
+ }
+
+ {
+ addResource();
+ mService->mSupportsSecureWithNonSecureCodec = true;
+
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+
+ mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
+
+ // client marked for pending removal from the same process got reclaimed
+ // first, even though there are lower priority process
+ CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+ verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+
+ // lower priority client got reclaimed
+ CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+ verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+
+ // clean up client 3 which still left
+ mService->removeClient(kTestPid2, getId(mTestClient3));
+ }
+ }
+
void testRemoveClient() {
addResource();
@@ -900,4 +950,8 @@
testOverridePid();
}
+TEST_F(ResourceManagerServiceTest, markClientForPendingRemoval) {
+ testMarkClientForPendingRemoval();
+}
+
} // namespace android