Merge "Move codec2 out of frameworks/av" into pi-dev
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 66e4400..4991e50 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -54,17 +54,18 @@
proto: {
export_proto_headers: true,
- type: "lite",
+ type: "lite",
},
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"libbase",
"libbinder",
- "libhidlbase",
+ "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-lite",
+ "libstagefright_foundation",
"libutils",
],
cflags: [
@@ -86,24 +87,25 @@
proto: {
export_proto_headers: true,
- type: "full",
+ type: "full",
},
shared_libs: [
"android.hardware.drm@1.0",
"android.hardware.drm@1.1",
"libbase",
"libbinder",
- "libhidlbase",
+ "libhidlbase",
"liblog",
"libmediametrics",
"libprotobuf-cpp-full",
+ "libstagefright_foundation",
"libutils",
],
cflags: [
// Suppress unused parameter and no error options. These cause problems
- // when using the map type in a proto definition.
- "-Wno-unused-parameter",
- "-Wno-error",
+ // when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ "-Wno-error",
],
}
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 5d97188..4e8ad52 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -32,6 +32,7 @@
#include <media/drm/DrmAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
#include <mediadrm/DrmHal.h>
@@ -63,9 +64,27 @@
// This constant corresponds to the PROPERTY_DEVICE_UNIQUE_ID constant
// in the MediaDrm API.
constexpr char kPropertyDeviceUniqueId[] = "deviceUniqueId";
+constexpr char kEqualsSign[] = "=";
+template<typename T>
+std::string toBase64StringNoPad(const T* data, size_t size) {
+ if (size == 0) {
+ return "";
+ }
+ CHECK(sizeof(data[0] == 1));
+
+ android::AString outputString;
+ encodeBase64(data, size, &outputString);
+ // Remove trailing equals padding if it exists.
+ while (outputString.size() > 0 && outputString.endsWith(kEqualsSign)) {
+ outputString.erase(outputString.size() - 1, 1);
+ }
+
+ return std::string(outputString.c_str(), outputString.size());
}
+} // anonymous namespace
+
namespace android {
#define INIT_CHECK() {if (mInitCheck != OK) return mInitCheck;}
@@ -101,15 +120,6 @@
return hidl_string(string.string());
}
-std::string toHexString(const std::string& str) {
- std::ostringstream out;
- out << std::hex << std::setfill('0');
- for (size_t i = 0; i < str.size(); i++) {
- out << std::setw(2) << (int)(str[i]);
- }
- return out.str();
-}
-
static DrmPlugin::SecurityLevel toSecurityLevel(SecurityLevel level) {
switch(level) {
case SecurityLevel::SW_SECURE_CRYPTO:
@@ -340,6 +350,7 @@
sp<IDrmPlugin> DrmHal::makeDrmPlugin(const sp<IDrmFactory>& factory,
const uint8_t uuid[16], const String8& appPackageName) {
+ mAppPackageName = appPackageName;
mMetrics.SetAppPackageName(appPackageName);
sp<IDrmPlugin> plugin;
@@ -1353,9 +1364,10 @@
if (result != OK) {
ALOGE("Failed to serialize framework metrics: %d", result);
}
- serializedMetrics = toHexString(serializedMetrics);
- if (!serializedMetrics.empty()) {
- item.setCString("serialized_metrics", serializedMetrics.c_str());
+ std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
+ serializedMetrics.size());
+ if (!b64EncodedMetrics.empty()) {
+ item.setCString("serialized_metrics", b64EncodedMetrics.c_str());
}
if (!item.selfrecord()) {
ALOGE("Failed to self record framework metrics");
@@ -1364,14 +1376,16 @@
void DrmHal::reportPluginMetrics() const
{
- Vector<uint8_t> metrics;
+ Vector<uint8_t> metricsVector;
String8 vendor;
String8 description;
if (getPropertyStringInternal(String8("vendor"), vendor) == OK &&
getPropertyStringInternal(String8("description"), description) == OK &&
- getPropertyByteArrayInternal(String8("metrics"), metrics) == OK) {
- status_t res = android::reportDrmPluginMetrics(
- metrics, vendor, description);
+ getPropertyByteArrayInternal(String8("metrics"), metricsVector) == OK) {
+ std::string metricsString = toBase64StringNoPad(metricsVector.array(),
+ metricsVector.size());
+ status_t res = android::reportDrmPluginMetrics(metricsString, vendor,
+ description, mAppPackageName);
if (res != OK) {
ALOGE("Metrics were retrieved but could not be reported: %d", res);
}
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 6c97f2b..5cb48bf 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -16,80 +16,35 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "PluginMetricsReporting"
-#include <utils/Log.h>
-#include <inttypes.h>
#include <media/PluginMetricsReporting.h>
-#include <media/MediaAnalyticsItem.h>
+#include <inttypes.h>
-#include "protos/metrics.pb.h"
+#include <media/MediaAnalyticsItem.h>
+#include <utils/Log.h>
+
namespace android {
namespace {
-using android::drm_metrics::MetricsGroup;
-using android::drm_metrics::MetricsGroup_Metric;
-using android::drm_metrics::MetricsGroup_Metric_MetricValue;
+constexpr char kSerializedMetricsField[] = "serialized_metrics";
-const char* const kParentAttribute = "/parent/external";
-
-status_t reportMetricsGroup(const MetricsGroup& metricsGroup,
- const String8& batchName,
- const int64_t* parentId) {
- MediaAnalyticsItem analyticsItem(batchName.c_str());
+status_t reportVendorMetrics(const std::string& metrics,
+ const String8& name,
+ const String8& appPackageName) {
+ MediaAnalyticsItem analyticsItem(name.c_str());
analyticsItem.generateSessionID();
- int64_t sessionId = analyticsItem.getSessionID();
- if (parentId != NULL) {
- analyticsItem.setInt64(kParentAttribute, *parentId);
- }
- // Report the package name.
- if (metricsGroup.has_app_package_name()) {
- std::string app_package_name(metricsGroup.app_package_name().c_str(),
- metricsGroup.app_package_name().size());
- analyticsItem.setPkgName(app_package_name);
- }
-
- for (int i = 0; i < metricsGroup.metric_size(); ++i) {
- const MetricsGroup_Metric& metric = metricsGroup.metric(i);
- if (!metric.has_name()) {
- ALOGE("Metric with no name.");
- return BAD_VALUE;
- }
-
- if (!metric.has_value()) {
- ALOGE("Metric with no value.");
- return BAD_VALUE;
- }
-
- const MetricsGroup_Metric_MetricValue& value = metric.value();
- if (value.has_int_value()) {
- analyticsItem.setInt64(metric.name().c_str(),
- value.int_value());
- } else if (value.has_double_value()) {
- analyticsItem.setDouble(metric.name().c_str(),
- value.double_value());
- } else if (value.has_string_value()) {
- analyticsItem.setCString(metric.name().c_str(),
- value.string_value().c_str());
- } else {
- ALOGE("Metric Value with no actual value.");
- return BAD_VALUE;
- }
+ std::string app_package_name(appPackageName.c_str(), appPackageName.size());
+ analyticsItem.setPkgName(app_package_name);
+ if (metrics.size() > 0) {
+ analyticsItem.setCString(kSerializedMetricsField, metrics.c_str());
}
if (!analyticsItem.selfrecord()) {
- ALOGE("selfrecord() returned false. sessioId %" PRId64, sessionId);
- }
-
- for (int i = 0; i < metricsGroup.metric_sub_group_size(); ++i) {
- const MetricsGroup& subGroup = metricsGroup.metric_sub_group(i);
- status_t res = reportMetricsGroup(subGroup, batchName, &sessionId);
- if (res != OK) {
- return res;
- }
+ ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem.getSessionID());
}
return OK;
@@ -111,21 +66,16 @@
} // namespace
-status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics,
+status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
const String8& vendor,
- const String8& description) {
- MetricsGroup root_metrics_group;
- if (!root_metrics_group.ParseFromArray(serializedMetrics.array(),
- serializedMetrics.size())) {
- ALOGE("Failure to parse.");
- return BAD_VALUE;
- }
+ const String8& description,
+ const String8& appPackageName) {
String8 name = String8::format("drm.vendor.%s.%s",
sanitize(vendor).c_str(),
sanitize(description).c_str());
- return reportMetricsGroup(root_metrics_group, name, NULL);
+ return reportVendorMetrics(b64EncodedMetrics, name, appPackageName);
}
} // namespace android
diff --git a/drm/libmediadrm/protos/metrics.proto b/drm/libmediadrm/protos/metrics.proto
index aa26f5f..6160e6f 100644
--- a/drm/libmediadrm/protos/metrics.proto
+++ b/drm/libmediadrm/protos/metrics.proto
@@ -18,33 +18,6 @@
package android.drm_metrics;
-// The MetricsGroup is a collection of metric name/value pair instances
-// that can be serialized and provided to a caller.
-message MetricsGroup {
- message Metric {
- message MetricValue {
- // Exactly one of the following values must be set.
- optional int64 int_value = 1;
- optional double double_value = 2;
- optional string string_value = 3;
- }
-
- // The name of the metric. Must be valid UTF-8. Required.
- optional string name = 1;
-
- // The value of the metric. Required.
- optional MetricValue value = 2;
- }
-
- // The list of name/value pairs of metrics.
- repeated Metric metric = 1;
-
- // Allow multiple sub groups of metrics.
- repeated MetricsGroup metric_sub_group = 2;
-
- // Name of the application package associated with the metrics.
- optional string app_package_name = 3;
-}
// This message contains the specific metrics captured by DrmMetrics. It is
// used for serializing and logging metrics.
@@ -72,7 +45,7 @@
// The Counter message is used to store a count value with an associated
// Attribute.
message Counter {
- optional int64 count = 1;
+ optional uint64 count = 1;
// Represents the attributes associated with this counter instance.
optional Attributes attributes = 2;
}
@@ -80,11 +53,11 @@
// The DistributionMetric is meant to capture the moments of a normally
// distributed (or approximately normal) value.
message DistributionMetric {
- optional double min = 1;
- optional double max = 2;
- optional double mean = 3;
+ optional float min = 1;
+ optional float max = 2;
+ optional float mean = 3;
optional double variance = 4;
- optional double operation_count = 5;
+ optional uint64 operation_count = 5;
// Represents the attributes assocated with this distribution metric
// instance.
@@ -93,9 +66,9 @@
message SessionLifetime {
// Start time of the session in milliseconds since epoch.
- optional int64 start_time_ms = 1;
+ optional uint64 start_time_ms = 1;
// End time of the session in milliseconds since epoch.
- optional int64 end_time_ms = 2;
+ optional uint64 end_time_ms = 2;
}
// The count of open session operations. Each instance has a specific error
diff --git a/include/media/TimeCheck.h b/include/media/TimeCheck.h
new file mode 120000
index 0000000..e3ef134
--- /dev/null
+++ b/include/media/TimeCheck.h
@@ -0,0 +1 @@
+../../media/libmedia/include/media/TimeCheck.h
\ No newline at end of file
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index 666d68a..26b8251 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -76,9 +76,14 @@
Vector<uint32_t> thumbnails;
Vector<uint32_t> dimgRefs;
+ Vector<uint32_t> cdscRefs;
size_t nextTileIndex;
};
+struct ExifItem {
+ off64_t offset;
+ size_t size;
+};
/////////////////////////////////////////////////////////////////////
//
@@ -473,7 +478,9 @@
uint32_t itemId() { return mItemId; }
- void apply(KeyedVector<uint32_t, ImageItem> &itemIdToItemMap) const;
+ void apply(
+ KeyedVector<uint32_t, ImageItem> &itemIdToItemMap,
+ KeyedVector<uint32_t, ExifItem> &itemIdToExifMap) const;
private:
uint32_t mItemId;
@@ -483,17 +490,20 @@
DISALLOW_EVIL_CONSTRUCTORS(ItemReference);
};
-void ItemReference::apply(KeyedVector<uint32_t, ImageItem> &itemIdToItemMap) const {
- ssize_t itemIndex = itemIdToItemMap.indexOfKey(mItemId);
-
- // ignore non-image items
- if (itemIndex < 0) {
- return;
- }
-
+void ItemReference::apply(
+ KeyedVector<uint32_t, ImageItem> &itemIdToItemMap,
+ KeyedVector<uint32_t, ExifItem> &itemIdToExifMap) const {
ALOGV("attach reference type 0x%x to item id %d)", type(), mItemId);
- if (type() == FOURCC('d', 'i', 'm', 'g')) {
+ switch(type()) {
+ case FOURCC('d', 'i', 'm', 'g'): {
+ ssize_t itemIndex = itemIdToItemMap.indexOfKey(mItemId);
+
+ // ignore non-image items
+ if (itemIndex < 0) {
+ return;
+ }
+
ImageItem &derivedImage = itemIdToItemMap.editValueAt(itemIndex);
if (!derivedImage.dimgRefs.empty()) {
ALOGW("dimgRefs if not clean!");
@@ -512,7 +522,16 @@
// mark the source image of the derivation as hidden
sourceImage.hidden = true;
}
- } else if (type() == FOURCC('t', 'h', 'm', 'b')) {
+ break;
+ }
+ case FOURCC('t', 'h', 'm', 'b'): {
+ ssize_t itemIndex = itemIdToItemMap.indexOfKey(mItemId);
+
+ // ignore non-image items
+ if (itemIndex < 0) {
+ return;
+ }
+
// mark thumbnail image as hidden, these can be retrieved if the client
// request thumbnail explicitly, but won't be exposed as displayables.
ImageItem &thumbImage = itemIdToItemMap.editValueAt(itemIndex);
@@ -532,11 +551,43 @@
}
masterImage.thumbnails.push_back(mItemId);
}
- } else if (type() == FOURCC('a', 'u', 'x', 'l')) {
+ break;
+ }
+ case FOURCC('c', 'd', 's', 'c'): {
+ ssize_t itemIndex = itemIdToExifMap.indexOfKey(mItemId);
+
+ // ignore non-exif block items
+ if (itemIndex < 0) {
+ return;
+ }
+
+ for (size_t i = 0; i < mRefs.size(); i++) {
+ itemIndex = itemIdToItemMap.indexOfKey(mRefs[i]);
+
+ // ignore non-image items
+ if (itemIndex < 0) {
+ continue;
+ }
+ ALOGV("Image item id %d uses metadata item id %d", mRefs[i], mItemId);
+ ImageItem &image = itemIdToItemMap.editValueAt(itemIndex);
+ image.cdscRefs.push_back(mItemId);
+ }
+ break;
+ }
+ case FOURCC('a', 'u', 'x', 'l'): {
+ ssize_t itemIndex = itemIdToItemMap.indexOfKey(mItemId);
+
+ // ignore non-image items
+ if (itemIndex < 0) {
+ return;
+ }
+
// mark auxiliary image as hidden
ImageItem &auxImage = itemIdToItemMap.editValueAt(itemIndex);
auxImage.hidden = true;
- } else {
+ break;
+ }
+ default:
ALOGW("ignoring unsupported ref type 0x%x", type());
}
}
@@ -1299,10 +1350,13 @@
for (size_t i = 0; i < mItemInfos.size(); i++) {
const ItemInfo &info = mItemInfos[i];
-
- // ignore non-image items
+ // Only handle 3 types of items, all others are ignored:
+ // 'grid': derived image from tiles
+ // 'hvc1': coded image (or tile)
+ // 'Exif': EXIF metadata
if (info.itemType != FOURCC('g', 'r', 'i', 'd') &&
- info.itemType != FOURCC('h', 'v', 'c', '1')) {
+ info.itemType != FOURCC('h', 'v', 'c', '1') &&
+ info.itemType != FOURCC('E', 'x', 'i', 'f')) {
continue;
}
@@ -1325,6 +1379,19 @@
return ERROR_MALFORMED;
}
+ if (info.itemType == FOURCC('E', 'x', 'i', 'f')) {
+ // Only add if the Exif data is non-empty. The first 4 bytes contain
+ // the offset to TIFF header, which the Exif parser doesn't use.
+ if (size > 4) {
+ ExifItem exifItem = {
+ .offset = offset,
+ .size = size,
+ };
+ mItemIdToExifMap.add(info.itemId, exifItem);
+ }
+ continue;
+ }
+
ImageItem image(info.itemType, info.itemId, info.hidden);
ALOGV("adding %s: itemId %d", image.isGrid() ? "grid" : "image", info.itemId);
@@ -1354,7 +1421,7 @@
}
for (size_t i = 0; i < mItemReferences.size(); i++) {
- mItemReferences[i]->apply(mItemIdToItemMap);
+ mItemReferences[i]->apply(mItemIdToItemMap, mItemIdToExifMap);
}
bool foundPrimary = false;
@@ -1574,6 +1641,34 @@
return OK;
}
+status_t ItemTable::getExifOffsetAndSize(off64_t *offset, size_t *size) {
+ if (!mImageItemsValid) {
+ return INVALID_OPERATION;
+ }
+
+ ssize_t itemIndex = mItemIdToItemMap.indexOfKey(mPrimaryItemId);
+
+ // this should not happen, something's seriously wrong.
+ if (itemIndex < 0) {
+ return INVALID_OPERATION;
+ }
+
+ const ImageItem &image = mItemIdToItemMap[itemIndex];
+ if (image.cdscRefs.size() == 0) {
+ return NAME_NOT_FOUND;
+ }
+
+ ssize_t exifIndex = mItemIdToExifMap.indexOfKey(image.cdscRefs[0]);
+ if (exifIndex < 0) {
+ return NAME_NOT_FOUND;
+ }
+
+ // skip the first 4-byte of the offset to TIFF header
+ *offset = mItemIdToExifMap[exifIndex].offset + 4;
+ *size = mItemIdToExifMap[exifIndex].size - 4;
+ return OK;
+}
+
} // namespace heif
} // namespace android
diff --git a/media/extractors/mp4/ItemTable.h b/media/extractors/mp4/ItemTable.h
index f4a69cc..536dcb0 100644
--- a/media/extractors/mp4/ItemTable.h
+++ b/media/extractors/mp4/ItemTable.h
@@ -32,6 +32,7 @@
struct AssociationEntry;
struct ImageItem;
+struct ExifItem;
struct ItemLoc;
struct ItemInfo;
struct ItemProperty;
@@ -55,6 +56,7 @@
status_t findThumbnailItem(const uint32_t imageIndex, uint32_t *itemIndex);
status_t getImageOffsetAndSize(
uint32_t *itemIndex, off64_t *offset, size_t *size);
+ status_t getExifOffsetAndSize(off64_t *offset, size_t *size);
protected:
~ItemTable();
@@ -78,6 +80,7 @@
bool mImageItemsValid;
uint32_t mCurrentItemIndex;
KeyedVector<uint32_t, ImageItem> mItemIdToItemMap;
+ KeyedVector<uint32_t, ExifItem> mItemIdToExifMap;
Vector<uint32_t> mDisplayables;
status_t parseIlocBox(off64_t offset, size_t size);
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index a9f66fa..07ef0e3 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -586,6 +586,12 @@
}
if (mIsHeif && (mItemTable != NULL) && (mItemTable->countImages() > 0)) {
+ off64_t exifOffset;
+ size_t exifSize;
+ if (mItemTable->getExifOffsetAndSize(&exifOffset, &exifSize) == OK) {
+ mFileMetaData.setInt64(kKeyExifOffset, (int64_t)exifOffset);
+ mFileMetaData.setInt64(kKeyExifSize, (int64_t)exifSize);
+ }
for (uint32_t imageIndex = 0;
imageIndex < mItemTable->countImages(); imageIndex++) {
sp<MetaData> meta = mItemTable->getImageMeta(imageIndex);
@@ -601,6 +607,7 @@
ALOGW("Extracting still images only");
err = OK;
}
+ mInitCheck = OK;
ALOGV("adding HEIF image track %u", imageIndex);
Track *track = new Track;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 6b25302..2a3e668 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -67,8 +67,6 @@
, mWakeupDelayNanos(AAudioProperty_getWakeupDelayMicros() * AAUDIO_NANOS_PER_MICROSECOND)
, mMinimumSleepNanos(AAudioProperty_getMinimumSleepMicros() * AAUDIO_NANOS_PER_MICROSECOND)
{
- ALOGD("%s - mWakeupDelayNanos = %d, mMinimumSleepNanos = %d",
- __func__, mWakeupDelayNanos, mMinimumSleepNanos);
}
AudioStreamInternal::~AudioStreamInternal() {
@@ -231,8 +229,7 @@
aaudio_result_t AudioStreamInternal::close() {
aaudio_result_t result = AAUDIO_OK;
- ALOGD("close(): mServiceStreamHandle = 0x%08X",
- mServiceStreamHandle);
+ ALOGD("%s(): mServiceStreamHandle = 0x%08X", __func__, mServiceStreamHandle);
if (mServiceStreamHandle != AAUDIO_HANDLE_INVALID) {
// Don't close a stream while it is running.
aaudio_stream_state_t currentState = getState();
@@ -243,8 +240,8 @@
result = waitForStateChange(currentState, &nextState,
timeoutNanoseconds);
if (result != AAUDIO_OK) {
- ALOGE("close() waitForStateChange() returned %d %s",
- result, AAudio_convertResultToText(result));
+ ALOGE("%s() waitForStateChange() returned %d %s",
+ __func__, result, AAudio_convertResultToText(result));
}
}
setState(AAUDIO_STREAM_STATE_CLOSING);
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 11b43c3..0c3b1fa 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -57,8 +57,7 @@
return result;
}
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("requestPauseInternal() mServiceStreamHandle invalid = 0x%08X",
- mServiceStreamHandle);
+ ALOGE("%s() mServiceStreamHandle invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -70,8 +69,7 @@
aaudio_result_t AudioStreamInternalPlay::requestFlush() {
if (mServiceStreamHandle == AAUDIO_HANDLE_INVALID) {
- ALOGE("AudioStreamInternal::requestFlush() mServiceStreamHandle invalid = 0x%08X",
- mServiceStreamHandle);
+ ALOGE("%s() mServiceStreamHandle invalid", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -86,7 +84,7 @@
// Bump offset so caller does not see the retrograde motion in getFramesRead().
int64_t offset = writeCounter - readCounter;
mFramesOffsetFromService += offset;
- ALOGD("advanceClientToMatchServerPosition() readN = %lld, writeN = %lld, offset = %lld",
+ ALOGV("%s() readN = %lld, writeN = %lld, offset = %lld", __func__,
(long long)readCounter, (long long)writeCounter, (long long)mFramesOffsetFromService);
// Force writeCounter to match readCounter.
@@ -100,9 +98,7 @@
// Write the data, block if needed and timeoutMillis > 0
aaudio_result_t AudioStreamInternalPlay::write(const void *buffer, int32_t numFrames,
- int64_t timeoutNanoseconds)
-
-{
+ int64_t timeoutNanoseconds) {
return processData((void *)buffer, numFrames, timeoutNanoseconds);
}
@@ -121,7 +117,7 @@
// Still haven't got any timestamps from server.
// Keep waiting until we get some valid timestamps then start writing to the
// current buffer position.
- ALOGD("processDataNow() wait for valid timestamps");
+ ALOGD("%s() wait for valid timestamps", __func__);
// Sleep very briefly and hope we get a timestamp soon.
*wakeTimePtr = currentNanoTime + (2000 * AAUDIO_NANOS_PER_MICROSECOND);
ATRACE_END();
@@ -203,8 +199,6 @@
aaudio_result_t AudioStreamInternalPlay::writeNowWithConversion(const void *buffer,
int32_t numFrames) {
- // ALOGD("AudioStreamInternal::writeNowWithConversion(%p, %d)",
- // buffer, numFrames);
WrappingBuffer wrappingBuffer;
uint8_t *byteBuffer = (uint8_t *) buffer;
int32_t framesLeft = numFrames;
@@ -249,7 +243,6 @@
int32_t framesWritten = numFrames - framesLeft;
mAudioEndpoint.advanceWriteIndex(framesWritten);
- // ALOGD("AudioStreamInternal::writeNowWithConversion() returns %d", framesWritten);
return framesWritten;
}
@@ -268,7 +261,6 @@
} else {
mLastFramesRead = framesRead;
}
- //ALOGD("AudioStreamInternalPlay::getFramesRead() returns %lld", (long long)framesRead);
return framesRead;
}
@@ -276,13 +268,13 @@
{
int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
+ mFramesOffsetFromService;
- //ALOGD("AudioStreamInternalPlay::getFramesWritten() returns %lld", (long long)framesWritten);
return framesWritten;
}
// Render audio in the application callback and then write the data to the stream.
void *AudioStreamInternalPlay::callbackLoop() {
+ ALOGD("%s() entering >>>>>>>>>>>>>>>", __func__);
aaudio_result_t result = AAUDIO_OK;
aaudio_data_callback_result_t callbackResult = AAUDIO_CALLBACK_RESULT_CONTINUE;
if (!isDataCallbackSet()) return NULL;
@@ -297,7 +289,6 @@
// Write audio data to stream. This is a BLOCKING WRITE!
result = write(mCallbackBuffer, mCallbackFrames, timeoutNanos);
if ((result != mCallbackFrames)) {
- ALOGE("AudioStreamInternalPlay(): callbackLoop: write() returned %d", result);
if (result >= 0) {
// Only wrote some of the frames requested. Must have timed out.
result = AAUDIO_ERROR_TIMEOUT;
@@ -306,13 +297,13 @@
break;
}
} else if (callbackResult == AAUDIO_CALLBACK_RESULT_STOP) {
- ALOGD("AudioStreamInternalPlay(): callback returned AAUDIO_CALLBACK_RESULT_STOP");
+ ALOGV("%s(): callback returned AAUDIO_CALLBACK_RESULT_STOP", __func__);
break;
}
}
- ALOGD("AudioStreamInternalPlay(): callbackLoop() exiting, result = %d, isActive() = %d",
- result, (int) isActive());
+ ALOGD("%s() exiting, result = %d, isActive() = %d <<<<<<<<<<<<<<",
+ __func__, result, (int) isActive());
return NULL;
}
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index c4465fd..61e03db 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -104,17 +104,17 @@
mErrorCallbackUserData = builder.getErrorCallbackUserData();
// This is very helpful for debugging in the future. Please leave it in.
- ALOGI("open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
+ ALOGI("open() rate = %d, channels = %d, format = %d, sharing = %s, dir = %s",
mSampleRate, mSamplesPerFrame, mFormat,
AudioStream_convertSharingModeToShortText(mSharingMode),
(getDirection() == AAUDIO_DIRECTION_OUTPUT) ? "OUTPUT" : "INPUT");
- ALOGI("open() device = %d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
+ ALOGI("open() device = %d, sessionId = %d, perfMode = %d, callback: %s with frames = %d",
mDeviceId,
mSessionId,
mPerformanceMode,
(isDataCallbackSet() ? "ON" : "OFF"),
mFramesPerDataCallback);
- ALOGI("open() usage = %d, contentType = %d, inputPreset = %d",
+ ALOGI("open() usage = %d, contentType = %d, inputPreset = %d",
mUsage, mContentType, mInputPreset);
return AAUDIO_OK;
@@ -242,6 +242,22 @@
return close();
}
+void AudioStream::setState(aaudio_stream_state_t state) {
+ ALOGV("%s(%p) from %d to %d", __func__, this, mState, state);
+ // CLOSED is a final state
+ if (mState == AAUDIO_STREAM_STATE_CLOSED) {
+ ALOGE("%s(%p) tried to set to %d but already CLOSED", __func__, this, state);
+
+ // Once DISCONNECTED, we can only move to CLOSED state.
+ } else if (mState == AAUDIO_STREAM_STATE_DISCONNECTED
+ && state != AAUDIO_STREAM_STATE_CLOSED) {
+ ALOGE("%s(%p) tried to set to %d but already DISCONNECTED", __func__, this, state);
+
+ } else {
+ mState = state;
+ }
+}
+
aaudio_result_t AudioStream::waitForStateChange(aaudio_stream_state_t currentState,
aaudio_stream_state_t *nextState,
int64_t timeoutNanoseconds)
@@ -313,7 +329,9 @@
setPeriodNanoseconds(periodNanoseconds);
int err = pthread_create(&mThread, nullptr, AudioStream_internalThreadProc, this);
if (err != 0) {
- return AAudioConvert_androidToAAudioResult(-errno);
+ android::status_t status = -errno;
+ ALOGE("createThread() - pthread_create() failed, %d", status);
+ return AAudioConvert_androidToAAudioResult(status);
} else {
// TODO Use AAudioThread or maybe AndroidThread
// Name the thread with an increasing index, "AAudio_#", for debugging.
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index c0db0f9..5273e36 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -471,16 +471,7 @@
mFormat = format;
}
- void setState(aaudio_stream_state_t state) {
- if (mState == AAUDIO_STREAM_STATE_CLOSED) {
- ; // CLOSED is a final state
- } else if (mState == AAUDIO_STREAM_STATE_DISCONNECTED
- && state != AAUDIO_STREAM_STATE_CLOSED) {
- ; // Once DISCONNECTED, we can only move to CLOSED state.
- } else {
- mState = state;
- }
- }
+ void setState(aaudio_stream_state_t state);
void setDeviceId(int32_t deviceId) {
mDeviceId = deviceId;
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 3358e35..873d836 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -24,6 +24,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <media/TimeCheck.h>
#include <private/android_filesystem_config.h>
#include "IAudioFlinger.h"
@@ -933,6 +934,8 @@
break;
}
+ TimeCheck check("IAudioFlinger");
+
switch (code) {
case CREATE_TRACK: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 8f5ff30..0b98502 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -27,6 +27,7 @@
#include <media/AudioEffect.h>
#include <media/IAudioPolicyService.h>
+#include <media/TimeCheck.h>
#include <private/android_filesystem_config.h>
#include <system/audio.h>
@@ -882,6 +883,8 @@
break;
}
+ TimeCheck check("IAudioPolicyService");
+
switch (code) {
case SET_DEVICE_CONNECTION_STATE: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 34b15a8..3990e69 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -18,7 +18,7 @@
vndk: {
enabled: true,
},
- srcs: ["AudioParameter.cpp", "TypeConverter.cpp"],
+ srcs: ["AudioParameter.cpp", "TypeConverter.cpp", "TimeCheck.cpp"],
cflags: [
"-Werror",
"-Wno-error=deprecated-declarations",
diff --git a/media/libmedia/TimeCheck.cpp b/media/libmedia/TimeCheck.cpp
new file mode 100644
index 0000000..dab5d4f
--- /dev/null
+++ b/media/libmedia/TimeCheck.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <media/TimeCheck.h>
+
+namespace android {
+
+/* static */
+sp<TimeCheck::TimeCheckThread> TimeCheck::getTimeCheckThread()
+{
+ static sp<TimeCheck::TimeCheckThread> sTimeCheckThread = new TimeCheck::TimeCheckThread();
+ return sTimeCheckThread;
+}
+
+TimeCheck::TimeCheck(const char *tag, uint32_t timeoutMs)
+ : mEndTimeNs(getTimeCheckThread()->startMonitoring(tag, timeoutMs))
+{
+}
+
+TimeCheck::~TimeCheck() {
+ getTimeCheckThread()->stopMonitoring(mEndTimeNs);
+}
+
+TimeCheck::TimeCheckThread::~TimeCheckThread()
+{
+ AutoMutex _l(mMutex);
+ requestExit();
+ mMonitorRequests.clear();
+ mCond.signal();
+}
+
+nsecs_t TimeCheck::TimeCheckThread::startMonitoring(const char *tag, uint32_t timeoutMs) {
+ Mutex::Autolock _l(mMutex);
+ nsecs_t endTimeNs = systemTime() + milliseconds(timeoutMs);
+ for (; mMonitorRequests.indexOfKey(endTimeNs) >= 0; ++endTimeNs);
+ mMonitorRequests.add(endTimeNs, tag);
+ mCond.signal();
+ return endTimeNs;
+}
+
+void TimeCheck::TimeCheckThread::stopMonitoring(nsecs_t endTimeNs) {
+ Mutex::Autolock _l(mMutex);
+ mMonitorRequests.removeItem(endTimeNs);
+ mCond.signal();
+}
+
+bool TimeCheck::TimeCheckThread::threadLoop()
+{
+ status_t status = TIMED_OUT;
+ const char *tag;
+ {
+ AutoMutex _l(mMutex);
+
+ if (exitPending()) {
+ return false;
+ }
+
+ nsecs_t endTimeNs = INT64_MAX;
+ // KeyedVector mMonitorRequests is ordered so take first entry as next timeout
+ if (mMonitorRequests.size() != 0) {
+ endTimeNs = mMonitorRequests.keyAt(0);
+ tag = mMonitorRequests.valueAt(0);
+ }
+
+ const nsecs_t waitTimeNs = endTimeNs - systemTime();
+ if (waitTimeNs > 0) {
+ status = mCond.waitRelative(mMutex, waitTimeNs);
+ }
+ }
+ LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "TimeCheck timeout for %s", tag);
+ return true;
+}
+
+}; // namespace android
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index b0e1cc8..f267f76 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -182,6 +182,7 @@
const Vector<sp<IDrmFactory>> mFactories;
sp<IDrmPlugin> mPlugin;
sp<drm::V1_1::IDrmPlugin> mPluginV1_1;
+ String8 mAppPackageName;
// Mutable to allow modification within GetPropertyByteArray.
mutable MediaDrmMetrics mMetrics;
diff --git a/media/libmedia/include/media/PluginMetricsReporting.h b/media/libmedia/include/media/PluginMetricsReporting.h
index 4a5a363..e00bd43 100644
--- a/media/libmedia/include/media/PluginMetricsReporting.h
+++ b/media/libmedia/include/media/PluginMetricsReporting.h
@@ -20,13 +20,13 @@
#include <utils/Errors.h>
#include <utils/String8.h>
-#include <utils/Vector.h>
namespace android {
-status_t reportDrmPluginMetrics(const Vector<uint8_t>& serializedMetrics,
+status_t reportDrmPluginMetrics(const std::string& b64EncodedMetrics,
const String8& vendorName,
- const String8& description);
+ const String8& description,
+ const String8& appPackageName);
} // namespace android
diff --git a/media/libmedia/include/media/TimeCheck.h b/media/libmedia/include/media/TimeCheck.h
new file mode 100644
index 0000000..6c5f656
--- /dev/null
+++ b/media/libmedia/include/media/TimeCheck.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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_TIME_CHECK_H
+#define ANDROID_TIME_CHECK_H
+
+#include <utils/KeyedVector.h>
+#include <utils/Thread.h>
+
+
+namespace android {
+
+// A class monitoring execution time for a code block (scoped variable) and causing an assert
+// if it exceeds a certain time
+
+class TimeCheck {
+public:
+
+ // The default timeout is chosen to be less than system server watchdog timeout
+ static constexpr uint32_t kDefaultTimeOutMs = 5000;
+
+ TimeCheck(const char *tag, uint32_t timeoutMs = kDefaultTimeOutMs);
+ ~TimeCheck();
+
+private:
+
+ class TimeCheckThread : public Thread {
+ public:
+
+ TimeCheckThread() {}
+ virtual ~TimeCheckThread() override;
+
+ nsecs_t startMonitoring(const char *tag, uint32_t timeoutMs);
+ void stopMonitoring(nsecs_t endTimeNs);
+
+ private:
+
+ // RefBase
+ virtual void onFirstRef() override { run("TimeCheckThread", PRIORITY_URGENT_AUDIO); }
+
+ // Thread
+ virtual bool threadLoop() override;
+
+ Condition mCond;
+ Mutex mMutex;
+ // using the end time in ns as key is OK given the risk is low that two entries
+ // are added in such a way that <add time> + <timeout> are the same for both.
+ KeyedVector< nsecs_t, const char*> mMonitorRequests;
+ };
+
+ static sp<TimeCheckThread> getTimeCheckThread();
+
+ const nsecs_t mEndTimeNs;
+};
+
+}; // namespace android
+
+#endif // ANDROID_TIME_CHECK_H
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 18e63f2..f1b7806 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -218,6 +218,8 @@
kKeyIccProfile = 'prof', // raw data, ICC profile data
kKeyIsPrimaryImage = 'prim', // bool (int32_t), image track is the primary image
kKeyFrameCount = 'nfrm', // int32_t, total number of frame in video track
+ kKeyExifOffset = 'exof', // int64_t, Exif data offset
+ kKeyExifSize = 'exsz', // int64_t, Exif data size
};
enum {
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index 9e96a2b..e5567dc 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -903,7 +903,6 @@
if (mPlayer == 0) {
return INVALID_OPERATION;
}
- return mPlayer->getPlaybackSettings(rate);
status_t ret = mPlayer->getPlaybackSettings(rate);
if (ret == NO_ERROR) {
ALOGV("getPlaybackSettings(%f, %f, %d, %d)",
@@ -925,7 +924,9 @@
status_t MediaPlayer2::getSyncSettings(
AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) {
Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
+ if (mPlayer == 0) {
+ return INVALID_OPERATION;
+ }
status_t ret = mPlayer->getSyncSettings(sync, videoFps);
if (ret == NO_ERROR) {
ALOGV("getSyncSettings(%u, %u, %f, %f)",
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 27b9a5d..4a7d6ca 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -307,6 +307,26 @@
return OK;
}
+status_t NuMediaExtractor::getExifOffsetSize(off64_t *offset, size_t *size) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mImpl == NULL) {
+ return -EINVAL;
+ }
+
+ sp<MetaData> meta = mImpl->getMetaData();
+
+ int64_t exifOffset, exifSize;
+ if (meta->findInt64(kKeyExifOffset, &exifOffset)
+ && meta->findInt64(kKeyExifSize, &exifSize)) {
+ *offset = (off64_t) exifOffset;
+ *size = (size_t) exifSize;
+
+ return OK;
+ }
+ return ERROR_UNSUPPORTED;
+}
+
status_t NuMediaExtractor::selectTrack(size_t index,
int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) {
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/bqhelper/Android.bp b/media/libstagefright/bqhelper/Android.bp
index 9febe12..4f46be7 100644
--- a/media/libstagefright/bqhelper/Android.bp
+++ b/media/libstagefright/bqhelper/Android.bp
@@ -6,6 +6,7 @@
},
srcs: [
+ "Conversion.cpp",
"FrameDropper.cpp",
"GraphicBufferSource.cpp",
"WProducerListener.cpp",
diff --git a/media/libstagefright/bqhelper/Conversion.cpp b/media/libstagefright/bqhelper/Conversion.cpp
new file mode 100644
index 0000000..ffed005
--- /dev/null
+++ b/media/libstagefright/bqhelper/Conversion.cpp
@@ -0,0 +1,1542 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/stagefright/bqhelper/Conversion.h>
+
+namespace android {
+namespace conversion {
+
+// native_handle_t helper functions.
+
+/**
+ * \brief Take an fd and create a native handle containing only the given fd.
+ * The created handle will need to be deleted manually with
+ * `native_handle_delete()`.
+ *
+ * \param[in] fd The source file descriptor (of type `int`).
+ * \return The create `native_handle_t*` that contains the given \p fd. If the
+ * supplied \p fd is negative, the created native handle will contain no file
+ * descriptors.
+ *
+ * If the native handle cannot be created, the return value will be
+ * `nullptr`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+native_handle_t* native_handle_create_from_fd(int fd) {
+ if (fd < 2) {
+ return native_handle_create(0, 0);
+ }
+ native_handle_t* nh = native_handle_create(1, 0);
+ if (nh == nullptr) {
+ return nullptr;
+ }
+ nh->data[0] = fd;
+ return nh;
+}
+
+/**
+ * \brief Extract a file descriptor from a native handle.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \param[in] index The index of the file descriptor in \p nh to read from. This
+ * input has the default value of `0`.
+ * \return The `index`-th file descriptor in \p nh. If \p nh does not have
+ * enough file descriptors, the returned value will be `-1`.
+ *
+ * This function does not duplicate the file descriptor.
+ */
+int native_handle_read_fd(native_handle_t const* nh, int index) {
+ return ((nh == nullptr) || (nh->numFds == 0) ||
+ (nh->numFds <= index) || (index < 0)) ?
+ -1 : nh->data[index];
+}
+
+/**
+ * Conversion functions
+ * ====================
+ *
+ * There are two main directions of conversion:
+ * - `inTargetType(...)`: Create a wrapper whose lifetime depends on the
+ * input. The wrapper has type `TargetType`.
+ * - `toTargetType(...)`: Create a standalone object of type `TargetType` that
+ * corresponds to the input. The lifetime of the output does not depend on the
+ * lifetime of the input.
+ * - `wrapIn(TargetType*, ...)`: Same as `inTargetType()`, but for `TargetType`
+ * that cannot be copied and/or moved efficiently, or when there are multiple
+ * output arguments.
+ * - `convertTo(TargetType*, ...)`: Same as `toTargetType()`, but for
+ * `TargetType` that cannot be copied and/or moved efficiently, or when there
+ * are multiple output arguments.
+ *
+ * `wrapIn()` and `convertTo()` functions will take output arguments before
+ * input arguments. Some of these functions might return a value to indicate
+ * success or error.
+ *
+ * In converting or wrapping something as a Treble type that contains a
+ * `hidl_handle`, `native_handle_t*` will need to be created and returned as
+ * an additional output argument, hence only `wrapIn()` or `convertTo()` would
+ * be available. The caller must call `native_handle_delete()` to deallocate the
+ * returned native handle when it is no longer needed.
+ *
+ * For types that contain file descriptors, `inTargetType()` and `wrapAs()` do
+ * not perform duplication of file descriptors, while `toTargetType()` and
+ * `convertTo()` do.
+ */
+
+/**
+ * \brief Convert `Return<void>` to `binder::Status`.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `binder::Status`.
+ */
+// convert: Return<void> -> ::android::binder::Status
+::android::binder::Status toBinderStatus(
+ Return<void> const& t) {
+ return ::android::binder::Status::fromExceptionCode(
+ t.isOk() ? OK : UNKNOWN_ERROR,
+ t.description().c_str());
+}
+
+/**
+ * \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
+ *
+ * \param[in] t The source `Return<void>`.
+ * \return The corresponding `status_t`.
+ */
+// convert: Return<void> -> status_t
+status_t toStatusT(Return<void> const& t) {
+ return t.isOk() ? OK : UNKNOWN_ERROR;
+}
+
+/**
+ * \brief Wrap `native_handle_t*` in `hidl_handle`.
+ *
+ * \param[in] nh The source `native_handle_t*`.
+ * \return The `hidl_handle` that points to \p nh.
+ */
+// wrap: native_handle_t* -> hidl_handle
+hidl_handle inHidlHandle(native_handle_t const* nh) {
+ return hidl_handle(nh);
+}
+
+/**
+ * \brief Convert `int32_t` to `Dataspace`.
+ *
+ * \param[in] l The source `int32_t`.
+ * \result The corresponding `Dataspace`.
+ */
+// convert: int32_t -> Dataspace
+Dataspace toHardwareDataspace(int32_t l) {
+ return static_cast<Dataspace>(l);
+}
+
+/**
+ * \brief Convert `Dataspace` to `int32_t`.
+ *
+ * \param[in] t The source `Dataspace`.
+ * \result The corresponding `int32_t`.
+ */
+// convert: Dataspace -> int32_t
+int32_t toRawDataspace(Dataspace const& t) {
+ return static_cast<int32_t>(t);
+}
+
+/**
+ * \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that points to the buffer.
+ */
+// wrap: void*, size_t -> hidl_vec<uint8_t>
+hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
+ hidl_vec<uint8_t> t;
+ t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
+ return t;
+}
+
+/**
+ * \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer.
+ *
+ * \param[in] l The pointer to the beginning of the opaque buffer.
+ * \param[in] size The size of the buffer.
+ * \return A `hidl_vec<uint8_t>` that is a copy of the input buffer.
+ */
+// convert: void*, size_t -> hidl_vec<uint8_t>
+hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size) {
+ hidl_vec<uint8_t> t;
+ t.resize(size);
+ uint8_t const* src = static_cast<uint8_t const*>(l);
+ std::copy(src, src + size, t.data());
+ return t;
+}
+
+/**
+ * \brief Wrap `GraphicBuffer` in `AnwBuffer`.
+ *
+ * \param[out] t The wrapper of type `AnwBuffer`.
+ * \param[in] l The source `GraphicBuffer`.
+ */
+// wrap: GraphicBuffer -> AnwBuffer
+void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
+ t->attr.width = l.getWidth();
+ t->attr.height = l.getHeight();
+ t->attr.stride = l.getStride();
+ t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
+ t->attr.layerCount = l.getLayerCount();
+ t->attr.usage = l.getUsage();
+ t->attr.id = l.getId();
+ t->attr.generationNumber = l.getGenerationNumber();
+ t->nativeHandle = hidl_handle(l.handle);
+}
+
+/**
+ * \brief Convert `AnwBuffer` to `GraphicBuffer`.
+ *
+ * \param[out] l The destination `GraphicBuffer`.
+ * \param[in] t The source `AnwBuffer`.
+ *
+ * This function will duplicate all file descriptors in \p t.
+ */
+// convert: AnwBuffer -> GraphicBuffer
+// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
+bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
+ native_handle_t* handle = t.nativeHandle == nullptr ?
+ nullptr : native_handle_clone(t.nativeHandle);
+
+ size_t const numInts = 12 + (handle ? handle->numInts : 0);
+ int32_t* ints = new int32_t[numInts];
+
+ size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
+ int* fds = new int[numFds];
+
+ ints[0] = 'GBFR';
+ ints[1] = static_cast<int32_t>(t.attr.width);
+ ints[2] = static_cast<int32_t>(t.attr.height);
+ ints[3] = static_cast<int32_t>(t.attr.stride);
+ ints[4] = static_cast<int32_t>(t.attr.format);
+ ints[5] = static_cast<int32_t>(t.attr.layerCount);
+ ints[6] = static_cast<int32_t>(t.attr.usage);
+ ints[7] = static_cast<int32_t>(t.attr.id >> 32);
+ ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
+ ints[9] = static_cast<int32_t>(t.attr.generationNumber);
+ ints[10] = 0;
+ ints[11] = 0;
+ if (handle) {
+ ints[10] = static_cast<int32_t>(handle->numFds);
+ ints[11] = static_cast<int32_t>(handle->numInts);
+ int* intsStart = handle->data + handle->numFds;
+ std::copy(handle->data, intsStart, fds);
+ std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
+ }
+
+ void const* constBuffer = static_cast<void const*>(ints);
+ size_t size = numInts * sizeof(int32_t);
+ int const* constFds = static_cast<int const*>(fds);
+ status_t status = l->unflatten(constBuffer, size, constFds, numFds);
+
+ delete [] fds;
+ delete [] ints;
+ native_handle_delete(handle);
+ return status == NO_ERROR;
+}
+
+/**
+ * Conversion functions for types outside media
+ * ============================================
+ *
+ * Some objects in libui and libgui that were made to go through binder calls do
+ * not expose ways to read or write their fields to the public. To pass an
+ * object of this kind through the HIDL boundary, translation functions need to
+ * work around the access restriction by using the publicly available
+ * `flatten()` and `unflatten()` functions.
+ *
+ * All `flatten()` and `unflatten()` overloads follow the same convention as
+ * follows:
+ *
+ * status_t flatten(ObjectType const& object,
+ * [OtherType const& other, ...]
+ * void*& buffer, size_t& size,
+ * int*& fds, size_t& numFds)
+ *
+ * status_t unflatten(ObjectType* object,
+ * [OtherType* other, ...,]
+ * void*& buffer, size_t& size,
+ * int*& fds, size_t& numFds)
+ *
+ * The number of `other` parameters varies depending on the `ObjectType`. For
+ * example, in the process of unflattening an object that contains
+ * `hidl_handle`, `other` is needed to hold `native_handle_t` objects that will
+ * be created.
+ *
+ * The last four parameters always work the same way in all overloads of
+ * `flatten()` and `unflatten()`:
+ * - For `flatten()`, `buffer` is the pointer to the non-fd buffer to be filled,
+ * `size` is the size (in bytes) of the non-fd buffer pointed to by `buffer`,
+ * `fds` is the pointer to the fd buffer to be filled, and `numFds` is the
+ * size (in ints) of the fd buffer pointed to by `fds`.
+ * - For `unflatten()`, `buffer` is the pointer to the non-fd buffer to be read
+ * from, `size` is the size (in bytes) of the non-fd buffer pointed to by
+ * `buffer`, `fds` is the pointer to the fd buffer to be read from, and
+ * `numFds` is the size (in ints) of the fd buffer pointed to by `fds`.
+ * - After a successful call to `flatten()` or `unflatten()`, `buffer` and `fds`
+ * will be advanced, while `size` and `numFds` will be decreased to reflect
+ * how much storage/data of the two buffers (fd and non-fd) have been used.
+ * - After an unsuccessful call, the values of `buffer`, `size`, `fds` and
+ * `numFds` are invalid.
+ *
+ * The return value of a successful `flatten()` or `unflatten()` call will be
+ * `OK` (also aliased as `NO_ERROR`). Any other values indicate a failure.
+ *
+ * For each object type that supports flattening, there will be two accompanying
+ * functions: `getFlattenedSize()` and `getFdCount()`. `getFlattenedSize()` will
+ * return the size of the non-fd buffer that the object will need for
+ * flattening. `getFdCount()` will return the size of the fd buffer that the
+ * object will need for flattening.
+ *
+ * The set of these four functions, `getFlattenedSize()`, `getFdCount()`,
+ * `flatten()` and `unflatten()`, are similar to functions of the same name in
+ * the abstract class `Flattenable`. The only difference is that functions in
+ * this file are not member functions of the object type. For example, we write
+ *
+ * flatten(x, buffer, size, fds, numFds)
+ *
+ * instead of
+ *
+ * x.flatten(buffer, size, fds, numFds)
+ *
+ * because we cannot modify the type of `x`.
+ *
+ * There is one exception to the naming convention: `hidl_handle` that
+ * represents a fence. The four functions for this "Fence" type have the word
+ * "Fence" attched to their names because the object type, which is
+ * `hidl_handle`, does not carry the special meaning that the object itself can
+ * only contain zero or one file descriptor.
+ */
+
+// Ref: frameworks/native/libs/ui/Fence.cpp
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return The required size of the flat buffer.
+ *
+ * The current version of this function always returns 4, which is the number of
+ * bytes required to store the number of file descriptors contained in the fd
+ * part of the flat buffer.
+ */
+size_t getFenceFlattenedSize(hidl_handle const& /* fence */) {
+ return 4;
+};
+
+/**
+ * \brief Return the number of file descriptors contained in a fence.
+ *
+ * \param[in] fence The input fence of type `hidl_handle`.
+ * \return `0` if \p fence does not contain a valid file descriptor, or `1`
+ * otherwise.
+ */
+size_t getFenceFdCount(hidl_handle const& fence) {
+ return native_handle_read_fd(fence) == -1 ? 0 : 1;
+}
+
+/**
+ * \brief Unflatten `Fence` to `hidl_handle`.
+ *
+ * \param[out] fence The destination `hidl_handle`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will point to a newly created
+ * native handle, which needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < 4) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numFdsInHandle;
+ FlattenableUtils::read(buffer, size, numFdsInHandle);
+
+ if (numFdsInHandle > 1) {
+ return BAD_VALUE;
+ }
+
+ if (numFds < numFdsInHandle) {
+ return NO_MEMORY;
+ }
+
+ if (numFdsInHandle) {
+ *nh = native_handle_create_from_fd(*fds);
+ if (*nh == nullptr) {
+ return NO_MEMORY;
+ }
+ *fence = *nh;
+ ++fds;
+ --numFds;
+ } else {
+ *nh = nullptr;
+ *fence = hidl_handle();
+ }
+
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `hidl_handle` as `Fence`.
+ *
+ * \param[in] t The source `hidl_handle`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t flattenFence(hidl_handle const& fence,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFenceFlattenedSize(fence) ||
+ numFds < getFenceFdCount(fence)) {
+ return NO_MEMORY;
+ }
+ // Cast to uint32_t since the size of a size_t can vary between 32- and
+ // 64-bit processes
+ FlattenableUtils::write(buffer, size,
+ static_cast<uint32_t>(getFenceFdCount(fence)));
+ int fd = native_handle_read_fd(fence);
+ if (fd != -1) {
+ *fds = fd;
+ ++fds;
+ --numFds;
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `Fence` in `hidl_handle`.
+ *
+ * \param[out] t The wrapper of type `hidl_handle`.
+ * \param[out] nh The native handle pointed to by \p t.
+ * \param[in] l The source `Fence`.
+ *
+ * On success, \p nh will hold a newly created native handle, which must be
+ * deleted manually with `native_handle_delete()` afterwards.
+ */
+// wrap: Fence -> hidl_handle
+bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) {
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflattenFence(t, nh, constBuffer, size, constFds, numFds)
+ != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `hidl_handle` to `Fence`.
+ *
+ * \param[out] l The destination `Fence`. `l` must not have been used
+ * (`l->isValid()` must return `false`) before this function is called.
+ * \param[in] t The source `hidl_handle`.
+ *
+ * If \p t contains a valid file descriptor, it will be duplicated.
+ */
+// convert: hidl_handle -> Fence
+bool convertTo(Fence* l, hidl_handle const& t) {
+ int fd = native_handle_read_fd(t);
+ if (fd != -1) {
+ fd = dup(fd);
+ if (fd == -1) {
+ return false;
+ }
+ }
+ native_handle_t* nh = native_handle_create_from_fd(fd);
+ if (nh == nullptr) {
+ if (fd != -1) {
+ close(fd);
+ }
+ return false;
+ }
+
+ size_t const baseSize = getFenceFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ size_t const baseNumFds = getFenceFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ native_handle_delete(nh);
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) {
+ native_handle_delete(nh);
+ return false;
+ }
+ native_handle_delete(nh);
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ constexpr size_t min = sizeof(t.state);
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ return min;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ return min + getFenceFlattenedSize(t.fence);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ return min + sizeof(
+ ::android::FenceTime::Snapshot::signalTime);
+ }
+ return 0;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FenceTimeSnapshot`.
+ *
+ * \param[in] t The input `FenceTimeSnapshot`.
+ * \return The number of file descriptors contained in \p snapshot.
+ */
+size_t getFdCount(
+ HGraphicBufferProducer::FenceTimeSnapshot const& t) {
+ return t.state ==
+ HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ?
+ getFenceFdCount(t.fence) : 0;
+}
+
+/**
+ * \brief Flatten `FenceTimeSnapshot`.
+ *
+ * \param[in] t The source `FenceTimeSnapshot`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence` if `t.state ==
+ * FENCE`.
+ */
+status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ switch (t.state) {
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::EMPTY);
+ return NO_ERROR;
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::FENCE);
+ return flattenFence(t.fence, buffer, size, fds, numFds);
+ case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
+ FlattenableUtils::write(buffer, size,
+ ::android::FenceTime::Snapshot::State::SIGNAL_TIME);
+ FlattenableUtils::write(buffer, size, t.signalTimeNs);
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Unflatten `FenceTimeSnapshot`.
+ *
+ * \param[out] t The destination `FenceTimeSnapshot`.
+ * \param[out] nh The underlying native handle.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and the constructed snapshot contains a
+ * file descriptor, \p nh will be created to hold that file descriptor. In this
+ * case, \p nh needs to be deleted with `native_handle_delete()` afterwards.
+ */
+status_t unflatten(
+ HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < sizeof(t->state)) {
+ return NO_MEMORY;
+ }
+
+ *nh = nullptr;
+ ::android::FenceTime::Snapshot::State state;
+ FlattenableUtils::read(buffer, size, state);
+ switch (state) {
+ case ::android::FenceTime::Snapshot::State::EMPTY:
+ t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY;
+ return NO_ERROR;
+ case ::android::FenceTime::Snapshot::State::FENCE:
+ t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE;
+ return unflattenFence(&t->fence, nh, buffer, size, fds, numFds);
+ case ::android::FenceTime::Snapshot::State::SIGNAL_TIME:
+ t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME;
+ if (size < sizeof(t->signalTimeNs)) {
+ return NO_MEMORY;
+ }
+ FlattenableUtils::read(buffer, size, t->signalTimeNs);
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
+
+/**
+ * \brief Return a lower bound on the size of the non-fd buffer required to
+ * flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& /* t */) {
+ return sizeof(uint64_t) + // mFrameNumber
+ sizeof(uint8_t) + // mIndex
+ sizeof(uint8_t) + // mAddPostCompositeCalled
+ sizeof(uint8_t) + // mAddRetireCalled
+ sizeof(uint8_t) + // mAddReleaseCalled
+ sizeof(nsecs_t) + // mPostedTime
+ sizeof(nsecs_t) + // mRequestedPresentTime
+ sizeof(nsecs_t) + // mLatchTime
+ sizeof(nsecs_t) + // mFirstRefreshStartTime
+ sizeof(nsecs_t); // mLastRefreshStartTime
+}
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return minFlattenedSize(t) +
+ getFlattenedSize(t.gpuCompositionDoneFence) +
+ getFlattenedSize(t.displayPresentFence) +
+ getFlattenedSize(t.displayRetireFence) +
+ getFlattenedSize(t.releaseFence);
+};
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `FrameEventsDelta`.
+ *
+ * \param[in] t The input `FrameEventsDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+ HGraphicBufferProducer::FrameEventsDelta const& t) {
+ return getFdCount(t.gpuCompositionDoneFence) +
+ getFdCount(t.displayPresentFence) +
+ getFdCount(t.displayRetireFence) +
+ getFdCount(t.releaseFence);
+};
+
+/**
+ * \brief Unflatten `FrameEventsDelta`.
+ *
+ * \param[out] t The destination `FrameEventsDelta`.
+ * \param[out] nh The underlying array of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will have length 4, and it will be
+ * populated with `nullptr` or newly created handles. Each non-null slot in \p
+ * nh will need to be deleted manually with `native_handle_delete()`.
+ */
+status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
+ std::vector<native_handle_t*>* nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < minFlattenedSize(*t)) {
+ return NO_MEMORY;
+ }
+ FlattenableUtils::read(buffer, size, t->frameNumber);
+
+ // These were written as uint8_t for alignment.
+ uint8_t temp = 0;
+ FlattenableUtils::read(buffer, size, temp);
+ size_t index = static_cast<size_t>(temp);
+ if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ t->index = static_cast<uint32_t>(index);
+
+ FlattenableUtils::read(buffer, size, temp);
+ t->addPostCompositeCalled = static_cast<bool>(temp);
+ FlattenableUtils::read(buffer, size, temp);
+ t->addRetireCalled = static_cast<bool>(temp);
+ FlattenableUtils::read(buffer, size, temp);
+ t->addReleaseCalled = static_cast<bool>(temp);
+
+ FlattenableUtils::read(buffer, size, t->postedTimeNs);
+ FlattenableUtils::read(buffer, size, t->requestedPresentTimeNs);
+ FlattenableUtils::read(buffer, size, t->latchTimeNs);
+ FlattenableUtils::read(buffer, size, t->firstRefreshStartTimeNs);
+ FlattenableUtils::read(buffer, size, t->lastRefreshStartTimeNs);
+ FlattenableUtils::read(buffer, size, t->dequeueReadyTime);
+
+ // Fences
+ HGraphicBufferProducer::FenceTimeSnapshot* tSnapshot[4];
+ tSnapshot[0] = &t->gpuCompositionDoneFence;
+ tSnapshot[1] = &t->displayPresentFence;
+ tSnapshot[2] = &t->displayRetireFence;
+ tSnapshot[3] = &t->releaseFence;
+ nh->resize(4);
+ for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+ status_t status = unflatten(
+ tSnapshot[snapshotIndex], &((*nh)[snapshotIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ while (snapshotIndex > 0) {
+ --snapshotIndex;
+ if ((*nh)[snapshotIndex] != nullptr) {
+ native_handle_delete((*nh)[snapshotIndex]);
+ }
+ }
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `FrameEventsDelta`.
+ *
+ * \param[in] t The source `FrameEventsDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
+// FrameEventsDelta::flatten
+status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+ void*& buffer, size_t& size, int*& fds, size_t numFds) {
+ // Check that t.index is within a valid range.
+ if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
+ || t.index > std::numeric_limits<uint8_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ FlattenableUtils::write(buffer, size, t.frameNumber);
+
+ // These are static_cast to uint8_t for alignment.
+ FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addRetireCalled));
+ FlattenableUtils::write(
+ buffer, size, static_cast<uint8_t>(t.addReleaseCalled));
+
+ FlattenableUtils::write(buffer, size, t.postedTimeNs);
+ FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs);
+ FlattenableUtils::write(buffer, size, t.latchTimeNs);
+ FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs);
+ FlattenableUtils::write(buffer, size, t.dequeueReadyTime);
+
+ // Fences
+ HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4];
+ tSnapshot[0] = &t.gpuCompositionDoneFence;
+ tSnapshot[1] = &t.displayPresentFence;
+ tSnapshot[2] = &t.displayRetireFence;
+ tSnapshot[3] = &t.releaseFence;
+ for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
+ status_t status = flatten(
+ *(tSnapshot[snapshotIndex]), buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
+
+/**
+ * \brief Return the size of the non-fd buffer required to flatten
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t size = 4 + // mDeltas.size()
+ sizeof(t.compositorTiming);
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ size += getFlattenedSize(t.deltas[i]);
+ }
+ return size;
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+ size_t numFds = 0;
+ for (size_t i = 0; i < t.deltas.size(); ++i) {
+ numFds += getFdCount(t.deltas[i]);
+ }
+ return numFds;
+}
+
+/**
+ * \brief Unflatten `FrameEventHistoryDelta`.
+ *
+ * \param[out] t The destination `FrameEventHistoryDelta`.
+ * \param[out] nh The underlying array of arrays of native handles.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR`, \p nh will be populated with `nullptr` or
+ * newly created handles. The second dimension of \p nh will be 4. Each non-null
+ * slot in \p nh will need to be deleted manually with `native_handle_delete()`.
+ */
+status_t unflatten(
+ HGraphicBufferProducer::FrameEventHistoryDelta* t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < 4) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, t->compositorTiming);
+
+ uint32_t deltaCount = 0;
+ FlattenableUtils::read(buffer, size, deltaCount);
+ if (static_cast<size_t>(deltaCount) >
+ ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ t->deltas.resize(deltaCount);
+ nh->resize(deltaCount);
+ for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) {
+ status_t status = unflatten(
+ &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]),
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `FrameEventHistoryDelta`.
+ *
+ * \param[in] t The source `FrameEventHistoryDelta`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate file descriptors contained in \p t.
+ */
+status_t flatten(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
+ return BAD_VALUE;
+ }
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, t.compositorTiming);
+
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
+ for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
+ status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Wrap `::android::FrameEventHistoryData` in
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `::android::FrameEventHistoryDelta`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ ::android::FrameEventHistoryDelta const& l) {
+
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
+ * `::android::FrameEventHistoryDelta`.
+ *
+ * \param[out] l The destination `::android::FrameEventHistoryDelta`.
+ * \param[in] t The source `HGraphicBufferProducer::FrameEventHistoryDelta`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+bool convertTo(
+ ::android::FrameEventHistoryDelta* l,
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
+
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = getFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = static_cast<int*>(baseFds.get());
+ size_t numFds = baseNumFds;
+ if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/ui/Region.cpp
+
+/**
+ * \brief Return the size of the buffer required to flatten `Region`.
+ *
+ * \param[in] t The input `Region`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(Region const& t) {
+ return sizeof(uint32_t) + t.size() * sizeof(::android::Rect);
+}
+
+/**
+ * \brief Unflatten `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t unflatten(Region* t, void const*& buffer, size_t& size) {
+ if (size < sizeof(uint32_t)) {
+ return NO_MEMORY;
+ }
+
+ uint32_t numRects = 0;
+ FlattenableUtils::read(buffer, size, numRects);
+ if (size < numRects * sizeof(Rect)) {
+ return NO_MEMORY;
+ }
+ if (numRects > (UINT32_MAX / sizeof(Rect))) {
+ return NO_MEMORY;
+ }
+
+ t->resize(numRects);
+ for (size_t r = 0; r < numRects; ++r) {
+ ::android::Rect rect(::android::Rect::EMPTY_RECT);
+ status_t status = rect.unflatten(buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ (*t)[r] = Rect{
+ static_cast<int32_t>(rect.left),
+ static_cast<int32_t>(rect.top),
+ static_cast<int32_t>(rect.right),
+ static_cast<int32_t>(rect.bottom)};
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Flatten `Region`.
+ *
+ * \param[in] t The source `Region`.
+ * \param[in,out] buffer The pointer to the flat buffer.
+ * \param[in,out] size The size of the flat buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ */
+status_t flatten(Region const& t, void*& buffer, size_t& size) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size()));
+ for (size_t r = 0; r < t.size(); ++r) {
+ ::android::Rect rect(
+ static_cast<int32_t>(t[r].left),
+ static_cast<int32_t>(t[r].top),
+ static_cast<int32_t>(t[r].right),
+ static_cast<int32_t>(t[r].bottom));
+ status_t status = rect.flatten(buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::advance(buffer, size, sizeof(rect));
+ }
+ return NO_ERROR;
+}
+
+/**
+ * \brief Convert `::android::Region` to `Region`.
+ *
+ * \param[out] t The destination `Region`.
+ * \param[in] l The source `::android::Region`.
+ */
+// convert: ::android::Region -> Region
+bool convertTo(Region* t, ::android::Region const& l) {
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ if (l.flatten(buffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ if (unflatten(t, constBuffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `Region` to `::android::Region`.
+ *
+ * \param[out] l The destination `::android::Region`.
+ * \param[in] t The source `Region`.
+ */
+// convert: Region -> ::android::Region
+bool convertTo(::android::Region* l, Region const& t) {
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ if (flatten(t, buffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ if (l->unflatten(constBuffer, size) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+// BGraphicBufferProducer::QueueBufferInput
+
+/**
+ * \brief Return a lower bound on the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return A lower bound on the size of the flat buffer.
+ */
+constexpr size_t minFlattenedSize(
+ HGraphicBufferProducer::QueueBufferInput const& /* t */) {
+ return sizeof(int64_t) + // timestamp
+ sizeof(int) + // isAutoTimestamp
+ sizeof(android_dataspace) + // dataSpace
+ sizeof(::android::Rect) + // crop
+ sizeof(int) + // scalingMode
+ sizeof(uint32_t) + // transform
+ sizeof(uint32_t) + // stickyTransform
+ sizeof(bool); // getFrameTimestamps
+}
+
+/**
+ * \brief Return the size of the buffer required to flatten
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The required size of the flat buffer.
+ */
+size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t) {
+ return minFlattenedSize(t) +
+ getFenceFlattenedSize(t.fence) +
+ getFlattenedSize(t.surfaceDamage) +
+ sizeof(HdrMetadata::validTypes);
+}
+
+/**
+ * \brief Return the number of file descriptors contained in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
+ * \return The number of file descriptors contained in \p t.
+ */
+size_t getFdCount(
+ HGraphicBufferProducer::QueueBufferInput const& t) {
+ return getFenceFdCount(t.fence);
+}
+
+/**
+ * \brief Flatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The native handle cloned from `t.fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * This function will duplicate the file descriptor in `t.fence`. */
+status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
+ native_handle_t** nh,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds) {
+ if (size < getFlattenedSize(t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::write(buffer, size, t.timestamp);
+ FlattenableUtils::write(buffer, size, static_cast<int>(t.isAutoTimestamp));
+ FlattenableUtils::write(buffer, size,
+ static_cast<android_dataspace_t>(t.dataSpace));
+ FlattenableUtils::write(buffer, size, ::android::Rect(
+ static_cast<int32_t>(t.crop.left),
+ static_cast<int32_t>(t.crop.top),
+ static_cast<int32_t>(t.crop.right),
+ static_cast<int32_t>(t.crop.bottom)));
+ FlattenableUtils::write(buffer, size, static_cast<int>(t.scalingMode));
+ FlattenableUtils::write(buffer, size, t.transform);
+ FlattenableUtils::write(buffer, size, t.stickyTransform);
+ FlattenableUtils::write(buffer, size, t.getFrameTimestamps);
+
+ *nh = t.fence.getNativeHandle() == nullptr ?
+ nullptr : native_handle_clone(t.fence);
+ status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = flatten(t.surfaceDamage, buffer, size);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0));
+ return NO_ERROR;
+}
+
+/**
+ * \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The destination `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in,out] buffer The pointer to the flat non-fd buffer.
+ * \param[in,out] size The size of the flat non-fd buffer.
+ * \param[in,out] fds The pointer to the flat fd buffer.
+ * \param[in,out] numFds The size of the flat fd buffer.
+ * \return `NO_ERROR` on success; other value on failure.
+ *
+ * If the return value is `NO_ERROR` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+status_t unflatten(
+ HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
+ if (size < minFlattenedSize(*t)) {
+ return NO_MEMORY;
+ }
+
+ FlattenableUtils::read(buffer, size, t->timestamp);
+ int lIsAutoTimestamp;
+ FlattenableUtils::read(buffer, size, lIsAutoTimestamp);
+ t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp);
+ android_dataspace_t lDataSpace;
+ FlattenableUtils::read(buffer, size, lDataSpace);
+ t->dataSpace = static_cast<Dataspace>(lDataSpace);
+ Rect lCrop;
+ FlattenableUtils::read(buffer, size, lCrop);
+ t->crop = Rect{
+ static_cast<int32_t>(lCrop.left),
+ static_cast<int32_t>(lCrop.top),
+ static_cast<int32_t>(lCrop.right),
+ static_cast<int32_t>(lCrop.bottom)};
+ int lScalingMode;
+ FlattenableUtils::read(buffer, size, lScalingMode);
+ t->scalingMode = static_cast<int32_t>(lScalingMode);
+ FlattenableUtils::read(buffer, size, t->transform);
+ FlattenableUtils::read(buffer, size, t->stickyTransform);
+ FlattenableUtils::read(buffer, size, t->getFrameTimestamps);
+
+ status_t status = unflattenFence(&(t->fence), nh,
+ buffer, size, fds, numFds);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ // HdrMetadata ignored
+ return unflatten(&(t->surfaceDamage), buffer, size);
+}
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferInput`.
+ * \param[out] nh The underlying native handle for `t->fence`.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If the return value is `true` and `t->fence` contains a valid file
+ * descriptor, \p nh will be a newly created native handle holding that file
+ * descriptor. \p nh needs to be deleted with `native_handle_delete()`
+ * afterwards.
+ */
+bool wrapAs(
+ HGraphicBufferProducer::QueueBufferInput* t,
+ native_handle_t** nh,
+ BGraphicBufferProducer::QueueBufferInput const& l) {
+
+ size_t const baseSize = l.getFlattenedSize();
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = l.getFdCount();
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferInput` to
+ * `BGraphicBufferProducer::QueueBufferInput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferInput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferInput`.
+ *
+ * If `t.fence` has a valid file descriptor, it will be duplicated.
+ */
+bool convertTo(
+ BGraphicBufferProducer::QueueBufferInput* l,
+ HGraphicBufferProducer::QueueBufferInput const& t) {
+
+ size_t const baseSize = getFlattenedSize(t);
+ std::unique_ptr<uint8_t[]> baseBuffer(
+ new (std::nothrow) uint8_t[baseSize]);
+ if (!baseBuffer) {
+ return false;
+ }
+
+ size_t const baseNumFds = getFdCount(t);
+ std::unique_ptr<int[]> baseFds(
+ new (std::nothrow) int[baseNumFds]);
+ if (!baseFds) {
+ return false;
+ }
+
+ void* buffer = static_cast<void*>(baseBuffer.get());
+ size_t size = baseSize;
+ int* fds = baseFds.get();
+ size_t numFds = baseNumFds;
+ native_handle_t* nh;
+ if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) {
+ return false;
+ }
+
+ void const* constBuffer = static_cast<void const*>(baseBuffer.get());
+ size = baseSize;
+ int const* constFds = static_cast<int const*>(baseFds.get());
+ numFds = baseNumFds;
+ if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
+ if (nh != nullptr) {
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
+ return false;
+ }
+
+ native_handle_delete(nh);
+ return true;
+}
+
+// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
+// BGraphicBufferProducer::QueueBufferOutput
+
+/**
+ * \brief Wrap `BGraphicBufferProducer::QueueBufferOutput` in
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] t The wrapper of type
+ * `HGraphicBufferProducer::QueueBufferOutput`.
+ * \param[out] nh The array of array of native handles that are referred to by
+ * members of \p t.
+ * \param[in] l The source `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * On success, each member of \p nh will be either `nullptr` or a newly created
+ * native handle. All the non-`nullptr` elements must be deleted individually
+ * with `native_handle_delete()`.
+ */
+// wrap: BGraphicBufferProducer::QueueBufferOutput ->
+// HGraphicBufferProducer::QueueBufferOutput
+bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
+ std::vector<std::vector<native_handle_t*> >* nh,
+ BGraphicBufferProducer::QueueBufferOutput const& l) {
+ if (!wrapAs(&(t->frameTimestamps), nh, l.frameTimestamps)) {
+ return false;
+ }
+ t->width = l.width;
+ t->height = l.height;
+ t->transformHint = l.transformHint;
+ t->numPendingBuffers = l.numPendingBuffers;
+ t->nextFrameNumber = l.nextFrameNumber;
+ t->bufferReplaced = l.bufferReplaced;
+ return true;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
+ * `BGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * \param[out] l The destination `BGraphicBufferProducer::QueueBufferOutput`.
+ * \param[in] t The source `HGraphicBufferProducer::QueueBufferOutput`.
+ *
+ * This function will duplicate all file descriptors contained in \p t.
+ */
+// convert: HGraphicBufferProducer::QueueBufferOutput ->
+// BGraphicBufferProducer::QueueBufferOutput
+bool convertTo(
+ BGraphicBufferProducer::QueueBufferOutput* l,
+ HGraphicBufferProducer::QueueBufferOutput const& t) {
+ if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) {
+ return false;
+ }
+ l->width = t.width;
+ l->height = t.height;
+ l->transformHint = t.transformHint;
+ l->numPendingBuffers = t.numPendingBuffers;
+ l->nextFrameNumber = t.nextFrameNumber;
+ l->bufferReplaced = t.bufferReplaced;
+ return true;
+}
+
+/**
+ * \brief Convert `BGraphicBufferProducer::DisconnectMode` to
+ * `HGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `BGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
+ */
+HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode(
+ BGraphicBufferProducer::DisconnectMode l) {
+ switch (l) {
+ case BGraphicBufferProducer::DisconnectMode::Api:
+ return HGraphicBufferProducer::DisconnectMode::API;
+ case BGraphicBufferProducer::DisconnectMode::AllLocal:
+ return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL;
+ }
+ return HGraphicBufferProducer::DisconnectMode::API;
+}
+
+/**
+ * \brief Convert `HGraphicBufferProducer::DisconnectMode` to
+ * `BGraphicBufferProducer::DisconnectMode`.
+ *
+ * \param[in] l The source `HGraphicBufferProducer::DisconnectMode`.
+ * \return The corresponding `BGraphicBufferProducer::DisconnectMode`.
+ */
+BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
+ HGraphicBufferProducer::DisconnectMode t) {
+ switch (t) {
+ case HGraphicBufferProducer::DisconnectMode::API:
+ return BGraphicBufferProducer::DisconnectMode::Api;
+ case HGraphicBufferProducer::DisconnectMode::ALL_LOCAL:
+ return BGraphicBufferProducer::DisconnectMode::AllLocal;
+ }
+ return BGraphicBufferProducer::DisconnectMode::Api;
+}
+
+} // namespace conversion
+} // namespace android
+
diff --git a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h
index c15fafa..60d8c1e 100644
--- a/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h
+++ b/media/libstagefright/bqhelper/include/media/stagefright/bqhelper/Conversion.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef MEDIA_STAGEFRIGHT_CONVERSION_H_
-#define MEDIA_STAGEFRIGHT_CONVERSION_H_
+#ifndef MEDIA_STAGEFRIGHT_BQHELPER_CONVERSION_H_
+#define MEDIA_STAGEFRIGHT_BQHELPER_CONVERSION_H_
#include <vector>
#include <list>
@@ -83,17 +83,7 @@
*
* This function does not duplicate the file descriptor.
*/
-inline native_handle_t* native_handle_create_from_fd(int fd) {
- if (fd < 2) {
- return native_handle_create(0, 0);
- }
- native_handle_t* nh = native_handle_create(1, 0);
- if (nh == nullptr) {
- return nullptr;
- }
- nh->data[0] = fd;
- return nh;
-}
+native_handle_t* native_handle_create_from_fd(int fd);
/**
* \brief Extract a file descriptor from a native handle.
@@ -106,11 +96,7 @@
*
* This function does not duplicate the file descriptor.
*/
-inline int native_handle_read_fd(native_handle_t const* nh, int index = 0) {
- return ((nh == nullptr) || (nh->numFds == 0) ||
- (nh->numFds <= index) || (index < 0)) ?
- -1 : nh->data[index];
-}
+int native_handle_read_fd(native_handle_t const* nh, int index = 0);
/**
* Conversion functions
@@ -151,12 +137,7 @@
* \return The corresponding `binder::Status`.
*/
// convert: Return<void> -> ::android::binder::Status
-inline ::android::binder::Status toBinderStatus(
- Return<void> const& t) {
- return ::android::binder::Status::fromExceptionCode(
- t.isOk() ? OK : UNKNOWN_ERROR,
- t.description().c_str());
-}
+::android::binder::Status toBinderStatus(Return<void> const& t);
/**
* \brief Convert `Return<void>` to `status_t`. This is for legacy binder calls.
@@ -165,9 +146,7 @@
* \return The corresponding `status_t`.
*/
// convert: Return<void> -> status_t
-inline status_t toStatusT(Return<void> const& t) {
- return t.isOk() ? OK : UNKNOWN_ERROR;
-}
+status_t toStatusT(Return<void> const& t);
/**
* \brief Wrap `native_handle_t*` in `hidl_handle`.
@@ -176,9 +155,7 @@
* \return The `hidl_handle` that points to \p nh.
*/
// wrap: native_handle_t* -> hidl_handle
-inline hidl_handle inHidlHandle(native_handle_t const* nh) {
- return hidl_handle(nh);
-}
+hidl_handle inHidlHandle(native_handle_t const* nh);
/**
* \brief Convert `int32_t` to `Dataspace`.
@@ -187,9 +164,7 @@
* \result The corresponding `Dataspace`.
*/
// convert: int32_t -> Dataspace
-inline Dataspace toHardwareDataspace(int32_t l) {
- return static_cast<Dataspace>(l);
-}
+Dataspace toHardwareDataspace(int32_t l);
/**
* \brief Convert `Dataspace` to `int32_t`.
@@ -198,9 +173,7 @@
* \result The corresponding `int32_t`.
*/
// convert: Dataspace -> int32_t
-inline int32_t toRawDataspace(Dataspace const& t) {
- return static_cast<int32_t>(t);
-}
+int32_t toRawDataspace(Dataspace const& t);
/**
* \brief Wrap an opaque buffer inside a `hidl_vec<uint8_t>`.
@@ -210,11 +183,7 @@
* \return A `hidl_vec<uint8_t>` that points to the buffer.
*/
// wrap: void*, size_t -> hidl_vec<uint8_t>
-inline hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size) {
- hidl_vec<uint8_t> t;
- t.setToExternal(static_cast<uint8_t*>(const_cast<void*>(l)), size, false);
- return t;
-}
+hidl_vec<uint8_t> inHidlBytes(void const* l, size_t size);
/**
* \brief Create a `hidl_vec<uint8_t>` that is a copy of an opaque buffer.
@@ -224,13 +193,7 @@
* \return A `hidl_vec<uint8_t>` that is a copy of the input buffer.
*/
// convert: void*, size_t -> hidl_vec<uint8_t>
-inline hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size) {
- hidl_vec<uint8_t> t;
- t.resize(size);
- uint8_t const* src = static_cast<uint8_t const*>(l);
- std::copy(src, src + size, t.data());
- return t;
-}
+hidl_vec<uint8_t> toHidlBytes(void const* l, size_t size);
/**
* \brief Wrap `GraphicBuffer` in `AnwBuffer`.
@@ -239,17 +202,7 @@
* \param[in] l The source `GraphicBuffer`.
*/
// wrap: GraphicBuffer -> AnwBuffer
-inline void wrapAs(AnwBuffer* t, GraphicBuffer const& l) {
- t->attr.width = l.getWidth();
- t->attr.height = l.getHeight();
- t->attr.stride = l.getStride();
- t->attr.format = static_cast<PixelFormat>(l.getPixelFormat());
- t->attr.layerCount = l.getLayerCount();
- t->attr.usage = l.getUsage();
- t->attr.id = l.getId();
- t->attr.generationNumber = l.getGenerationNumber();
- t->nativeHandle = hidl_handle(l.handle);
-}
+void wrapAs(AnwBuffer* t, GraphicBuffer const& l);
/**
* \brief Convert `AnwBuffer` to `GraphicBuffer`.
@@ -261,46 +214,7 @@
*/
// convert: AnwBuffer -> GraphicBuffer
// Ref: frameworks/native/libs/ui/GraphicBuffer.cpp: GraphicBuffer::flatten
-inline bool convertTo(GraphicBuffer* l, AnwBuffer const& t) {
- native_handle_t* handle = t.nativeHandle == nullptr ?
- nullptr : native_handle_clone(t.nativeHandle);
-
- size_t const numInts = 12 + (handle ? handle->numInts : 0);
- int32_t* ints = new int32_t[numInts];
-
- size_t numFds = static_cast<size_t>(handle ? handle->numFds : 0);
- int* fds = new int[numFds];
-
- ints[0] = 'GBFR';
- ints[1] = static_cast<int32_t>(t.attr.width);
- ints[2] = static_cast<int32_t>(t.attr.height);
- ints[3] = static_cast<int32_t>(t.attr.stride);
- ints[4] = static_cast<int32_t>(t.attr.format);
- ints[5] = static_cast<int32_t>(t.attr.layerCount);
- ints[6] = static_cast<int32_t>(t.attr.usage);
- ints[7] = static_cast<int32_t>(t.attr.id >> 32);
- ints[8] = static_cast<int32_t>(t.attr.id & 0xFFFFFFFF);
- ints[9] = static_cast<int32_t>(t.attr.generationNumber);
- ints[10] = 0;
- ints[11] = 0;
- if (handle) {
- ints[10] = static_cast<int32_t>(handle->numFds);
- ints[11] = static_cast<int32_t>(handle->numInts);
- int* intsStart = handle->data + handle->numFds;
- std::copy(handle->data, intsStart, fds);
- std::copy(intsStart, intsStart + handle->numInts, &ints[12]);
- }
-
- void const* constBuffer = static_cast<void const*>(ints);
- size_t size = numInts * sizeof(int32_t);
- int const* constFds = static_cast<int const*>(fds);
- status_t status = l->unflatten(constBuffer, size, constFds, numFds);
-
- delete [] fds;
- delete [] ints;
- native_handle_delete(handle);
- return status == NO_ERROR;
-}
+bool convertTo(GraphicBuffer* l, AnwBuffer const& t);
/**
* Conversion functions for types outside media
@@ -387,9 +301,7 @@
* bytes required to store the number of file descriptors contained in the fd
* part of the flat buffer.
*/
-inline size_t getFenceFlattenedSize(hidl_handle const& /* fence */) {
- return 4;
-};
+size_t getFenceFlattenedSize(hidl_handle const& fence);
/**
* \brief Return the number of file descriptors contained in a fence.
@@ -398,9 +310,7 @@
* \return `0` if \p fence does not contain a valid file descriptor, or `1`
* otherwise.
*/
-inline size_t getFenceFdCount(hidl_handle const& fence) {
- return native_handle_read_fd(fence) == -1 ? 0 : 1;
-}
+size_t getFenceFdCount(hidl_handle const& fence);
/**
* \brief Unflatten `Fence` to `hidl_handle`.
@@ -417,38 +327,8 @@
* native handle, which needs to be deleted with `native_handle_delete()`
* afterwards.
*/
-inline status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < 4) {
- return NO_MEMORY;
- }
-
- uint32_t numFdsInHandle;
- FlattenableUtils::read(buffer, size, numFdsInHandle);
-
- if (numFdsInHandle > 1) {
- return BAD_VALUE;
- }
-
- if (numFds < numFdsInHandle) {
- return NO_MEMORY;
- }
-
- if (numFdsInHandle) {
- *nh = native_handle_create_from_fd(*fds);
- if (*nh == nullptr) {
- return NO_MEMORY;
- }
- *fence = *nh;
- ++fds;
- --numFds;
- } else {
- *nh = nullptr;
- *fence = hidl_handle();
- }
-
- return NO_ERROR;
-}
+status_t unflattenFence(hidl_handle* fence, native_handle_t** nh,
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
/**
* \brief Flatten `hidl_handle` as `Fence`.
@@ -460,24 +340,8 @@
* \param[in,out] numFds The size of the flat fd buffer.
* \return `NO_ERROR` on success; other value on failure.
*/
-inline status_t flattenFence(hidl_handle const& fence,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (size < getFenceFlattenedSize(fence) ||
- numFds < getFenceFdCount(fence)) {
- return NO_MEMORY;
- }
- // Cast to uint32_t since the size of a size_t can vary between 32- and
- // 64-bit processes
- FlattenableUtils::write(buffer, size,
- static_cast<uint32_t>(getFenceFdCount(fence)));
- int fd = native_handle_read_fd(fence);
- if (fd != -1) {
- *fds = fd;
- ++fds;
- --numFds;
- }
- return NO_ERROR;
-}
+status_t flattenFence(hidl_handle const& fence,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds);
/**
* \brief Wrap `Fence` in `hidl_handle`.
@@ -490,40 +354,7 @@
* deleted manually with `native_handle_delete()` afterwards.
*/
// wrap: Fence -> hidl_handle
-inline bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l) {
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = static_cast<int*>(baseFds.get());
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflattenFence(t, nh, constBuffer, size, constFds, numFds)
- != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+bool wrapAs(hidl_handle* t, native_handle_t** nh, Fence const& l);
/**
* \brief Convert `hidl_handle` to `Fence`.
@@ -535,58 +366,7 @@
* If \p t contains a valid file descriptor, it will be duplicated.
*/
// convert: hidl_handle -> Fence
-inline bool convertTo(Fence* l, hidl_handle const& t) {
- int fd = native_handle_read_fd(t);
- if (fd != -1) {
- fd = dup(fd);
- if (fd == -1) {
- return false;
- }
- }
- native_handle_t* nh = native_handle_create_from_fd(fd);
- if (nh == nullptr) {
- if (fd != -1) {
- close(fd);
- }
- return false;
- }
-
- size_t const baseSize = getFenceFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- native_handle_delete(nh);
- return false;
- }
-
- size_t const baseNumFds = getFenceFdCount(t);
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- native_handle_delete(nh);
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = static_cast<int*>(baseFds.get());
- size_t numFds = baseNumFds;
- if (flattenFence(hidl_handle(nh), buffer, size, fds, numFds) != NO_ERROR) {
- native_handle_delete(nh);
- return false;
- }
- native_handle_delete(nh);
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+bool convertTo(Fence* l, hidl_handle const& t);
// Ref: frameworks/native/libs/ui/FenceTime.cpp: FenceTime::Snapshot
@@ -597,20 +377,7 @@
* \param[in] t The input `FenceTimeSnapshot`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(
- HGraphicBufferProducer::FenceTimeSnapshot const& t) {
- constexpr size_t min = sizeof(t.state);
- switch (t.state) {
- case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
- return min;
- case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
- return min + getFenceFlattenedSize(t.fence);
- case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
- return min + sizeof(
- ::android::FenceTime::Snapshot::signalTime);
- }
- return 0;
-}
+size_t getFlattenedSize(HGraphicBufferProducer::FenceTimeSnapshot const& t);
/**
* \brief Return the number of file descriptors contained in
@@ -619,12 +386,7 @@
* \param[in] t The input `FenceTimeSnapshot`.
* \return The number of file descriptors contained in \p snapshot.
*/
-inline size_t getFdCount(
- HGraphicBufferProducer::FenceTimeSnapshot const& t) {
- return t.state ==
- HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE ?
- getFenceFdCount(t.fence) : 0;
-}
+size_t getFdCount(HGraphicBufferProducer::FenceTimeSnapshot const& t);
/**
* \brief Flatten `FenceTimeSnapshot`.
@@ -639,29 +401,8 @@
* This function will duplicate the file descriptor in `t.fence` if `t.state ==
* FENCE`.
*/
-inline status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- switch (t.state) {
- case HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY:
- FlattenableUtils::write(buffer, size,
- ::android::FenceTime::Snapshot::State::EMPTY);
- return NO_ERROR;
- case HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE:
- FlattenableUtils::write(buffer, size,
- ::android::FenceTime::Snapshot::State::FENCE);
- return flattenFence(t.fence, buffer, size, fds, numFds);
- case HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME:
- FlattenableUtils::write(buffer, size,
- ::android::FenceTime::Snapshot::State::SIGNAL_TIME);
- FlattenableUtils::write(buffer, size, t.signalTimeNs);
- return NO_ERROR;
- }
- return NO_ERROR;
-}
+status_t flatten(HGraphicBufferProducer::FenceTimeSnapshot const& t,
+ void*& buffer, size_t& size, int*& fds, size_t& numFds);
/**
* \brief Unflatten `FenceTimeSnapshot`.
@@ -678,72 +419,20 @@
* file descriptor, \p nh will be created to hold that file descriptor. In this
* case, \p nh needs to be deleted with `native_handle_delete()` afterwards.
*/
-inline status_t unflatten(
+status_t unflatten(
HGraphicBufferProducer::FenceTimeSnapshot* t, native_handle_t** nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < sizeof(t->state)) {
- return NO_MEMORY;
- }
-
- *nh = nullptr;
- ::android::FenceTime::Snapshot::State state;
- FlattenableUtils::read(buffer, size, state);
- switch (state) {
- case ::android::FenceTime::Snapshot::State::EMPTY:
- t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::EMPTY;
- return NO_ERROR;
- case ::android::FenceTime::Snapshot::State::FENCE:
- t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::FENCE;
- return unflattenFence(&t->fence, nh, buffer, size, fds, numFds);
- case ::android::FenceTime::Snapshot::State::SIGNAL_TIME:
- t->state = HGraphicBufferProducer::FenceTimeSnapshot::State::SIGNAL_TIME;
- if (size < sizeof(t->signalTimeNs)) {
- return NO_MEMORY;
- }
- FlattenableUtils::read(buffer, size, t->signalTimeNs);
- return NO_ERROR;
- }
- return NO_ERROR;
-}
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventsDelta
/**
- * \brief Return a lower bound on the size of the non-fd buffer required to
- * flatten `FrameEventsDelta`.
- *
- * \param[in] t The input `FrameEventsDelta`.
- * \return A lower bound on the size of the flat buffer.
- */
-constexpr size_t minFlattenedSize(
- HGraphicBufferProducer::FrameEventsDelta const& /* t */) {
- return sizeof(uint64_t) + // mFrameNumber
- sizeof(uint8_t) + // mIndex
- sizeof(uint8_t) + // mAddPostCompositeCalled
- sizeof(uint8_t) + // mAddRetireCalled
- sizeof(uint8_t) + // mAddReleaseCalled
- sizeof(nsecs_t) + // mPostedTime
- sizeof(nsecs_t) + // mRequestedPresentTime
- sizeof(nsecs_t) + // mLatchTime
- sizeof(nsecs_t) + // mFirstRefreshStartTime
- sizeof(nsecs_t); // mLastRefreshStartTime
-}
-
-/**
* \brief Return the size of the non-fd buffer required to flatten
* `FrameEventsDelta`.
*
* \param[in] t The input `FrameEventsDelta`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(
- HGraphicBufferProducer::FrameEventsDelta const& t) {
- return minFlattenedSize(t) +
- getFlattenedSize(t.gpuCompositionDoneFence) +
- getFlattenedSize(t.displayPresentFence) +
- getFlattenedSize(t.displayRetireFence) +
- getFlattenedSize(t.releaseFence);
-};
+size_t getFlattenedSize(HGraphicBufferProducer::FrameEventsDelta const& t);
/**
* \brief Return the number of file descriptors contained in
@@ -752,13 +441,7 @@
* \param[in] t The input `FrameEventsDelta`.
* \return The number of file descriptors contained in \p t.
*/
-inline size_t getFdCount(
- HGraphicBufferProducer::FrameEventsDelta const& t) {
- return getFdCount(t.gpuCompositionDoneFence) +
- getFdCount(t.displayPresentFence) +
- getFdCount(t.displayRetireFence) +
- getFdCount(t.releaseFence);
-};
+size_t getFdCount(HGraphicBufferProducer::FrameEventsDelta const& t);
/**
* \brief Unflatten `FrameEventsDelta`.
@@ -775,60 +458,9 @@
* populated with `nullptr` or newly created handles. Each non-null slot in \p
* nh will need to be deleted manually with `native_handle_delete()`.
*/
-inline status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
+status_t unflatten(HGraphicBufferProducer::FrameEventsDelta* t,
std::vector<native_handle_t*>* nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < minFlattenedSize(*t)) {
- return NO_MEMORY;
- }
- FlattenableUtils::read(buffer, size, t->frameNumber);
-
- // These were written as uint8_t for alignment.
- uint8_t temp = 0;
- FlattenableUtils::read(buffer, size, temp);
- size_t index = static_cast<size_t>(temp);
- if (index >= ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- t->index = static_cast<uint32_t>(index);
-
- FlattenableUtils::read(buffer, size, temp);
- t->addPostCompositeCalled = static_cast<bool>(temp);
- FlattenableUtils::read(buffer, size, temp);
- t->addRetireCalled = static_cast<bool>(temp);
- FlattenableUtils::read(buffer, size, temp);
- t->addReleaseCalled = static_cast<bool>(temp);
-
- FlattenableUtils::read(buffer, size, t->postedTimeNs);
- FlattenableUtils::read(buffer, size, t->requestedPresentTimeNs);
- FlattenableUtils::read(buffer, size, t->latchTimeNs);
- FlattenableUtils::read(buffer, size, t->firstRefreshStartTimeNs);
- FlattenableUtils::read(buffer, size, t->lastRefreshStartTimeNs);
- FlattenableUtils::read(buffer, size, t->dequeueReadyTime);
-
- // Fences
- HGraphicBufferProducer::FenceTimeSnapshot* tSnapshot[4];
- tSnapshot[0] = &t->gpuCompositionDoneFence;
- tSnapshot[1] = &t->displayPresentFence;
- tSnapshot[2] = &t->displayRetireFence;
- tSnapshot[3] = &t->releaseFence;
- nh->resize(4);
- for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
- status_t status = unflatten(
- tSnapshot[snapshotIndex], &((*nh)[snapshotIndex]),
- buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- while (snapshotIndex > 0) {
- --snapshotIndex;
- if ((*nh)[snapshotIndex] != nullptr) {
- native_handle_delete((*nh)[snapshotIndex]);
- }
- }
- return status;
- }
- }
- return NO_ERROR;
-}
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
/**
* \brief Flatten `FrameEventsDelta`.
@@ -844,47 +476,8 @@
*/
// Ref: frameworks/native/libs/gui/FrameTimestamp.cpp:
// FrameEventsDelta::flatten
-inline status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
- void*& buffer, size_t& size, int*& fds, size_t numFds) {
- // Check that t.index is within a valid range.
- if (t.index >= static_cast<uint32_t>(FrameEventHistory::MAX_FRAME_HISTORY)
- || t.index > std::numeric_limits<uint8_t>::max()) {
- return BAD_VALUE;
- }
-
- FlattenableUtils::write(buffer, size, t.frameNumber);
-
- // These are static_cast to uint8_t for alignment.
- FlattenableUtils::write(buffer, size, static_cast<uint8_t>(t.index));
- FlattenableUtils::write(
- buffer, size, static_cast<uint8_t>(t.addPostCompositeCalled));
- FlattenableUtils::write(
- buffer, size, static_cast<uint8_t>(t.addRetireCalled));
- FlattenableUtils::write(
- buffer, size, static_cast<uint8_t>(t.addReleaseCalled));
-
- FlattenableUtils::write(buffer, size, t.postedTimeNs);
- FlattenableUtils::write(buffer, size, t.requestedPresentTimeNs);
- FlattenableUtils::write(buffer, size, t.latchTimeNs);
- FlattenableUtils::write(buffer, size, t.firstRefreshStartTimeNs);
- FlattenableUtils::write(buffer, size, t.lastRefreshStartTimeNs);
- FlattenableUtils::write(buffer, size, t.dequeueReadyTime);
-
- // Fences
- HGraphicBufferProducer::FenceTimeSnapshot const* tSnapshot[4];
- tSnapshot[0] = &t.gpuCompositionDoneFence;
- tSnapshot[1] = &t.displayPresentFence;
- tSnapshot[2] = &t.displayRetireFence;
- tSnapshot[3] = &t.releaseFence;
- for (size_t snapshotIndex = 0; snapshotIndex < 4; ++snapshotIndex) {
- status_t status = flatten(
- *(tSnapshot[snapshotIndex]), buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
+status_t flatten(HGraphicBufferProducer::FrameEventsDelta const& t,
+ void*& buffer, size_t& size, int*& fds, size_t numFds);
// Ref: frameworks/native/libs/gui/FrameTimestamps.cpp: FrameEventHistoryDelta
@@ -895,15 +488,8 @@
* \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(
- HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
- size_t size = 4 + // mDeltas.size()
- sizeof(t.compositorTiming);
- for (size_t i = 0; i < t.deltas.size(); ++i) {
- size += getFlattenedSize(t.deltas[i]);
- }
- return size;
-}
+size_t getFlattenedSize(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t);
/**
* \brief Return the number of file descriptors contained in
@@ -912,14 +498,8 @@
* \param[in] t The input `HGraphicBufferProducer::FrameEventHistoryDelta`.
* \return The number of file descriptors contained in \p t.
*/
-inline size_t getFdCount(
- HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
- size_t numFds = 0;
- for (size_t i = 0; i < t.deltas.size(); ++i) {
- numFds += getFdCount(t.deltas[i]);
- }
- return numFds;
-}
+size_t getFdCount(
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t);
/**
* \brief Unflatten `FrameEventHistoryDelta`.
@@ -936,34 +516,10 @@
* newly created handles. The second dimension of \p nh will be 4. Each non-null
* slot in \p nh will need to be deleted manually with `native_handle_delete()`.
*/
-inline status_t unflatten(
+status_t unflatten(
HGraphicBufferProducer::FrameEventHistoryDelta* t,
std::vector<std::vector<native_handle_t*> >* nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < 4) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::read(buffer, size, t->compositorTiming);
-
- uint32_t deltaCount = 0;
- FlattenableUtils::read(buffer, size, deltaCount);
- if (static_cast<size_t>(deltaCount) >
- ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- t->deltas.resize(deltaCount);
- nh->resize(deltaCount);
- for (size_t deltaIndex = 0; deltaIndex < deltaCount; ++deltaIndex) {
- status_t status = unflatten(
- &(t->deltas[deltaIndex]), &((*nh)[deltaIndex]),
- buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
/**
* \brief Flatten `FrameEventHistoryDelta`.
@@ -977,27 +533,9 @@
*
* This function will duplicate file descriptors contained in \p t.
*/
-inline status_t flatten(
+status_t flatten(
HGraphicBufferProducer::FrameEventHistoryDelta const& t,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (t.deltas.size() > ::android::FrameEventHistory::MAX_FRAME_HISTORY) {
- return BAD_VALUE;
- }
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, t.compositorTiming);
-
- FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.deltas.size()));
- for (size_t deltaIndex = 0; deltaIndex < t.deltas.size(); ++deltaIndex) {
- status_t status = flatten(t.deltas[deltaIndex], buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- }
- return NO_ERROR;
-}
+ void*& buffer, size_t& size, int*& fds, size_t& numFds);
/**
* \brief Wrap `::android::FrameEventHistoryData` in
@@ -1013,42 +551,9 @@
* native handle. All the non-`nullptr` elements must be deleted individually
* with `native_handle_delete()`.
*/
-inline bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
+bool wrapAs(HGraphicBufferProducer::FrameEventHistoryDelta* t,
std::vector<std::vector<native_handle_t*> >* nh,
- ::android::FrameEventHistoryDelta const& l) {
-
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+ ::android::FrameEventHistoryDelta const& l);
/**
* \brief Convert `HGraphicBufferProducer::FrameEventHistoryDelta` to
@@ -1059,42 +564,9 @@
*
* This function will duplicate all file descriptors contained in \p t.
*/
-inline bool convertTo(
+bool convertTo(
::android::FrameEventHistoryDelta* l,
- HGraphicBufferProducer::FrameEventHistoryDelta const& t) {
-
- size_t const baseSize = getFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = getFdCount(t);
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = static_cast<int*>(baseFds.get());
- size_t numFds = baseNumFds;
- if (flatten(t, buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+ HGraphicBufferProducer::FrameEventHistoryDelta const& t);
// Ref: frameworks/native/libs/ui/Region.cpp
@@ -1104,9 +576,7 @@
* \param[in] t The input `Region`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(Region const& t) {
- return sizeof(uint32_t) + t.size() * sizeof(::android::Rect);
-}
+size_t getFlattenedSize(Region const& t);
/**
* \brief Unflatten `Region`.
@@ -1116,36 +586,7 @@
* \param[in,out] size The size of the flat buffer.
* \return `NO_ERROR` on success; other value on failure.
*/
-inline status_t unflatten(Region* t, void const*& buffer, size_t& size) {
- if (size < sizeof(uint32_t)) {
- return NO_MEMORY;
- }
-
- uint32_t numRects = 0;
- FlattenableUtils::read(buffer, size, numRects);
- if (size < numRects * sizeof(Rect)) {
- return NO_MEMORY;
- }
- if (numRects > (UINT32_MAX / sizeof(Rect))) {
- return NO_MEMORY;
- }
-
- t->resize(numRects);
- for (size_t r = 0; r < numRects; ++r) {
- ::android::Rect rect(::android::Rect::EMPTY_RECT);
- status_t status = rect.unflatten(buffer, size);
- if (status != NO_ERROR) {
- return status;
- }
- FlattenableUtils::advance(buffer, size, sizeof(rect));
- (*t)[r] = Rect{
- static_cast<int32_t>(rect.left),
- static_cast<int32_t>(rect.top),
- static_cast<int32_t>(rect.right),
- static_cast<int32_t>(rect.bottom)};
- }
- return NO_ERROR;
-}
+status_t unflatten(Region* t, void const*& buffer, size_t& size);
/**
* \brief Flatten `Region`.
@@ -1155,26 +596,7 @@
* \param[in,out] size The size of the flat buffer.
* \return `NO_ERROR` on success; other value on failure.
*/
-inline status_t flatten(Region const& t, void*& buffer, size_t& size) {
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, static_cast<uint32_t>(t.size()));
- for (size_t r = 0; r < t.size(); ++r) {
- ::android::Rect rect(
- static_cast<int32_t>(t[r].left),
- static_cast<int32_t>(t[r].top),
- static_cast<int32_t>(t[r].right),
- static_cast<int32_t>(t[r].bottom));
- status_t status = rect.flatten(buffer, size);
- if (status != NO_ERROR) {
- return status;
- }
- FlattenableUtils::advance(buffer, size, sizeof(rect));
- }
- return NO_ERROR;
-}
+status_t flatten(Region const& t, void*& buffer, size_t& size);
/**
* \brief Convert `::android::Region` to `Region`.
@@ -1183,28 +605,7 @@
* \param[in] l The source `::android::Region`.
*/
// convert: ::android::Region -> Region
-inline bool convertTo(Region* t, ::android::Region const& l) {
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- if (l.flatten(buffer, size) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- if (unflatten(t, constBuffer, size) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+bool convertTo(Region* t, ::android::Region const& l);
/**
* \brief Convert `Region` to `::android::Region`.
@@ -1213,64 +614,19 @@
* \param[in] t The source `Region`.
*/
// convert: Region -> ::android::Region
-inline bool convertTo(::android::Region* l, Region const& t) {
- size_t const baseSize = getFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- if (flatten(t, buffer, size) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- if (l->unflatten(constBuffer, size) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+bool convertTo(::android::Region* l, Region const& t);
// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
// BGraphicBufferProducer::QueueBufferInput
/**
- * \brief Return a lower bound on the size of the buffer required to flatten
- * `HGraphicBufferProducer::QueueBufferInput`.
- *
- * \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
- * \return A lower bound on the size of the flat buffer.
- */
-constexpr size_t minFlattenedSize(
- HGraphicBufferProducer::QueueBufferInput const& /* t */) {
- return sizeof(int64_t) + // timestamp
- sizeof(int) + // isAutoTimestamp
- sizeof(android_dataspace) + // dataSpace
- sizeof(::android::Rect) + // crop
- sizeof(int) + // scalingMode
- sizeof(uint32_t) + // transform
- sizeof(uint32_t) + // stickyTransform
- sizeof(bool); // getFrameTimestamps
-}
-
-/**
* \brief Return the size of the buffer required to flatten
* `HGraphicBufferProducer::QueueBufferInput`.
*
* \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
* \return The required size of the flat buffer.
*/
-inline size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t) {
- return minFlattenedSize(t) +
- getFenceFlattenedSize(t.fence) +
- getFlattenedSize(t.surfaceDamage) +
- sizeof(HdrMetadata::validTypes);
-}
+size_t getFlattenedSize(HGraphicBufferProducer::QueueBufferInput const& t);
/**
* \brief Return the number of file descriptors contained in
@@ -1279,11 +635,8 @@
* \param[in] t The input `HGraphicBufferProducer::QueueBufferInput`.
* \return The number of file descriptors contained in \p t.
*/
-inline size_t getFdCount(
- HGraphicBufferProducer::QueueBufferInput const& t) {
- return getFenceFdCount(t.fence);
-}
-
+size_t getFdCount(
+ HGraphicBufferProducer::QueueBufferInput const& t);
/**
* \brief Flatten `HGraphicBufferProducer::QueueBufferInput`.
*
@@ -1296,40 +649,9 @@
* \return `NO_ERROR` on success; other value on failure.
*
* This function will duplicate the file descriptor in `t.fence`. */
-inline status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
+status_t flatten(HGraphicBufferProducer::QueueBufferInput const& t,
native_handle_t** nh,
- void*& buffer, size_t& size, int*& fds, size_t& numFds) {
- if (size < getFlattenedSize(t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::write(buffer, size, t.timestamp);
- FlattenableUtils::write(buffer, size, static_cast<int>(t.isAutoTimestamp));
- FlattenableUtils::write(buffer, size,
- static_cast<android_dataspace_t>(t.dataSpace));
- FlattenableUtils::write(buffer, size, ::android::Rect(
- static_cast<int32_t>(t.crop.left),
- static_cast<int32_t>(t.crop.top),
- static_cast<int32_t>(t.crop.right),
- static_cast<int32_t>(t.crop.bottom)));
- FlattenableUtils::write(buffer, size, static_cast<int>(t.scalingMode));
- FlattenableUtils::write(buffer, size, t.transform);
- FlattenableUtils::write(buffer, size, t.stickyTransform);
- FlattenableUtils::write(buffer, size, t.getFrameTimestamps);
-
- *nh = t.fence.getNativeHandle() == nullptr ?
- nullptr : native_handle_clone(t.fence);
- status_t status = flattenFence(hidl_handle(*nh), buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- status = flatten(t.surfaceDamage, buffer, size);
- if (status != NO_ERROR) {
- return status;
- }
- FlattenableUtils::write(buffer, size, decltype(HdrMetadata::validTypes)(0));
- return NO_ERROR;
-}
+ void*& buffer, size_t& size, int*& fds, size_t& numFds);
/**
* \brief Unflatten `HGraphicBufferProducer::QueueBufferInput`.
@@ -1347,42 +669,9 @@
* descriptor. \p nh needs to be deleted with `native_handle_delete()`
* afterwards.
*/
-inline status_t unflatten(
+status_t unflatten(
HGraphicBufferProducer::QueueBufferInput* t, native_handle_t** nh,
- void const*& buffer, size_t& size, int const*& fds, size_t& numFds) {
- if (size < minFlattenedSize(*t)) {
- return NO_MEMORY;
- }
-
- FlattenableUtils::read(buffer, size, t->timestamp);
- int lIsAutoTimestamp;
- FlattenableUtils::read(buffer, size, lIsAutoTimestamp);
- t->isAutoTimestamp = static_cast<int32_t>(lIsAutoTimestamp);
- android_dataspace_t lDataSpace;
- FlattenableUtils::read(buffer, size, lDataSpace);
- t->dataSpace = static_cast<Dataspace>(lDataSpace);
- Rect lCrop;
- FlattenableUtils::read(buffer, size, lCrop);
- t->crop = Rect{
- static_cast<int32_t>(lCrop.left),
- static_cast<int32_t>(lCrop.top),
- static_cast<int32_t>(lCrop.right),
- static_cast<int32_t>(lCrop.bottom)};
- int lScalingMode;
- FlattenableUtils::read(buffer, size, lScalingMode);
- t->scalingMode = static_cast<int32_t>(lScalingMode);
- FlattenableUtils::read(buffer, size, t->transform);
- FlattenableUtils::read(buffer, size, t->stickyTransform);
- FlattenableUtils::read(buffer, size, t->getFrameTimestamps);
-
- status_t status = unflattenFence(&(t->fence), nh,
- buffer, size, fds, numFds);
- if (status != NO_ERROR) {
- return status;
- }
- // HdrMetadata ignored
- return unflatten(&(t->surfaceDamage), buffer, size);
-}
+ void const*& buffer, size_t& size, int const*& fds, size_t& numFds);
/**
* \brief Wrap `BGraphicBufferProducer::QueueBufferInput` in
@@ -1398,43 +687,10 @@
* descriptor. \p nh needs to be deleted with `native_handle_delete()`
* afterwards.
*/
-inline bool wrapAs(
+bool wrapAs(
HGraphicBufferProducer::QueueBufferInput* t,
native_handle_t** nh,
- BGraphicBufferProducer::QueueBufferInput const& l) {
-
- size_t const baseSize = l.getFlattenedSize();
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = l.getFdCount();
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- if (l.flatten(buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (unflatten(t, nh, constBuffer, size, constFds, numFds) != NO_ERROR) {
- return false;
- }
-
- return true;
-}
+ BGraphicBufferProducer::QueueBufferInput const& l);
/**
* \brief Convert `HGraphicBufferProducer::QueueBufferInput` to
@@ -1445,48 +701,9 @@
*
* If `t.fence` has a valid file descriptor, it will be duplicated.
*/
-inline bool convertTo(
+bool convertTo(
BGraphicBufferProducer::QueueBufferInput* l,
- HGraphicBufferProducer::QueueBufferInput const& t) {
-
- size_t const baseSize = getFlattenedSize(t);
- std::unique_ptr<uint8_t[]> baseBuffer(
- new (std::nothrow) uint8_t[baseSize]);
- if (!baseBuffer) {
- return false;
- }
-
- size_t const baseNumFds = getFdCount(t);
- std::unique_ptr<int[]> baseFds(
- new (std::nothrow) int[baseNumFds]);
- if (!baseFds) {
- return false;
- }
-
- void* buffer = static_cast<void*>(baseBuffer.get());
- size_t size = baseSize;
- int* fds = baseFds.get();
- size_t numFds = baseNumFds;
- native_handle_t* nh;
- if (flatten(t, &nh, buffer, size, fds, numFds) != NO_ERROR) {
- return false;
- }
-
- void const* constBuffer = static_cast<void const*>(baseBuffer.get());
- size = baseSize;
- int const* constFds = static_cast<int const*>(baseFds.get());
- numFds = baseNumFds;
- if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- if (nh != nullptr) {
- native_handle_close(nh);
- native_handle_delete(nh);
- }
- return false;
- }
-
- native_handle_delete(nh);
- return true;
-}
+ HGraphicBufferProducer::QueueBufferInput const& t);
// Ref: frameworks/native/libs/gui/BGraphicBufferProducer.cpp:
// BGraphicBufferProducer::QueueBufferOutput
@@ -1507,20 +724,9 @@
*/
// wrap: BGraphicBufferProducer::QueueBufferOutput ->
// HGraphicBufferProducer::QueueBufferOutput
-inline bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
+bool wrapAs(HGraphicBufferProducer::QueueBufferOutput* t,
std::vector<std::vector<native_handle_t*> >* nh,
- BGraphicBufferProducer::QueueBufferOutput const& l) {
- if (!wrapAs(&(t->frameTimestamps), nh, l.frameTimestamps)) {
- return false;
- }
- t->width = l.width;
- t->height = l.height;
- t->transformHint = l.transformHint;
- t->numPendingBuffers = l.numPendingBuffers;
- t->nextFrameNumber = l.nextFrameNumber;
- t->bufferReplaced = l.bufferReplaced;
- return true;
-}
+ BGraphicBufferProducer::QueueBufferOutput const& l);
/**
* \brief Convert `HGraphicBufferProducer::QueueBufferOutput` to
@@ -1533,20 +739,9 @@
*/
// convert: HGraphicBufferProducer::QueueBufferOutput ->
// BGraphicBufferProducer::QueueBufferOutput
-inline bool convertTo(
+bool convertTo(
BGraphicBufferProducer::QueueBufferOutput* l,
- HGraphicBufferProducer::QueueBufferOutput const& t) {
- if (!convertTo(&(l->frameTimestamps), t.frameTimestamps)) {
- return false;
- }
- l->width = t.width;
- l->height = t.height;
- l->transformHint = t.transformHint;
- l->numPendingBuffers = t.numPendingBuffers;
- l->nextFrameNumber = t.nextFrameNumber;
- l->bufferReplaced = t.bufferReplaced;
- return true;
-}
+ HGraphicBufferProducer::QueueBufferOutput const& t);
/**
* \brief Convert `BGraphicBufferProducer::DisconnectMode` to
@@ -1555,16 +750,8 @@
* \param[in] l The source `BGraphicBufferProducer::DisconnectMode`.
* \return The corresponding `HGraphicBufferProducer::DisconnectMode`.
*/
-inline HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode(
- BGraphicBufferProducer::DisconnectMode l) {
- switch (l) {
- case BGraphicBufferProducer::DisconnectMode::Api:
- return HGraphicBufferProducer::DisconnectMode::API;
- case BGraphicBufferProducer::DisconnectMode::AllLocal:
- return HGraphicBufferProducer::DisconnectMode::ALL_LOCAL;
- }
- return HGraphicBufferProducer::DisconnectMode::API;
-}
+HGraphicBufferProducer::DisconnectMode toHidlDisconnectMode(
+ BGraphicBufferProducer::DisconnectMode l);
/**
* \brief Convert `HGraphicBufferProducer::DisconnectMode` to
@@ -1573,18 +760,10 @@
* \param[in] l The source `HGraphicBufferProducer::DisconnectMode`.
* \return The corresponding `BGraphicBufferProducer::DisconnectMode`.
*/
-inline BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
- HGraphicBufferProducer::DisconnectMode t) {
- switch (t) {
- case HGraphicBufferProducer::DisconnectMode::API:
- return BGraphicBufferProducer::DisconnectMode::Api;
- case HGraphicBufferProducer::DisconnectMode::ALL_LOCAL:
- return BGraphicBufferProducer::DisconnectMode::AllLocal;
- }
- return BGraphicBufferProducer::DisconnectMode::Api;
-}
+BGraphicBufferProducer::DisconnectMode toGuiDisconnectMode(
+ HGraphicBufferProducer::DisconnectMode t);
} // namespace conversion
} // namespace android
-#endif // MEDIA_STAGEFRIGHT_CONVERSION_H_
+#endif // MEDIA_STAGEFRIGHT_BQHELPER_CONVERSION_H_
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.h b/media/libstagefright/codecs/on2/dec/SoftVPX.h
index 9ac2791..b62b526 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.h
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.h
@@ -44,7 +44,7 @@
private:
enum {
- kNumBuffers = 16
+ kNumBuffers = 10
};
enum {
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 675c932..54a7095 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -71,6 +71,8 @@
status_t getFileFormat(sp<AMessage> *format) const;
+ status_t getExifOffsetSize(off64_t *offset, size_t *size) const;
+
status_t selectTrack(size_t index, int64_t startTimeUs = -1ll,
MediaSource::ReadOptions::SeekMode mode =
MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 8ef7620..cd0f75c 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -563,6 +563,10 @@
DescribeColorAspectsParams* colorAspectsParams =
(DescribeColorAspectsParams *)params;
+ if (!isValidOMXParam(colorAspectsParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
return OMX_ErrorBadParameter;
}
@@ -584,6 +588,10 @@
DescribeHDRStaticInfoParams* hdrStaticInfoParams =
(DescribeHDRStaticInfoParams *)params;
+ if (!isValidOMXParam(hdrStaticInfoParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
return OMX_ErrorBadPortIndex;
}
@@ -635,15 +643,17 @@
const DescribeHDRStaticInfoParams* hdrStaticInfoParams =
(DescribeHDRStaticInfoParams *)params;
+ if (!isValidOMXParam(hdrStaticInfoParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
return OMX_ErrorBadPortIndex;
}
- if (hdrStaticInfoParams != NULL) {
- mOutputFormat = OMX_COLOR_FormatYUV420Planar16;
- mHdrStaticInfo = hdrStaticInfoParams->sInfo;
- updatePortDefinitions(false);
- }
+ mOutputFormat = OMX_COLOR_FormatYUV420Planar16;
+ mHdrStaticInfo = hdrStaticInfoParams->sInfo;
+ updatePortDefinitions(false);
return OMX_ErrorNone;
}
diff --git a/packages/MediaComponents/Android.mk b/packages/MediaComponents/Android.mk
index b6480a2..b0d8e7d 100644
--- a/packages/MediaComponents/Android.mk
+++ b/packages/MediaComponents/Android.mk
@@ -40,9 +40,6 @@
LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
-# TODO: Enable proguard (b/74090741)
-LOCAL_PROGUARD_ENABLED := disabled
-
LOCAL_MULTILIB := first
LOCAL_JAVA_LIBRARIES += android-support-annotations
diff --git a/packages/MediaComponents/res/layout/full_transport_controls.xml b/packages/MediaComponents/res/layout/full_transport_controls.xml
index dd41a1f..0914785 100644
--- a/packages/MediaComponents/res/layout/full_transport_controls.xml
+++ b/packages/MediaComponents/res/layout/full_transport_controls.xml
@@ -28,4 +28,4 @@
<ImageButton android:id="@+id/pause" style="@style/FullTransportControlsButton.Pause" />
<ImageButton android:id="@+id/ffwd" style="@style/FullTransportControlsButton.Ffwd" />
<ImageButton android:id="@+id/next" style="@style/FullTransportControlsButton.Next" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/MediaComponents/res/layout/media_controller.xml b/packages/MediaComponents/res/layout/media_controller.xml
index c5fbee8..dfda840 100644
--- a/packages/MediaComponents/res/layout/media_controller.xml
+++ b/packages/MediaComponents/res/layout/media_controller.xml
@@ -105,6 +105,7 @@
android:id="@+id/cast"
android:layout_centerVertical="true"
android:visibility="gone"
+ android:contentDescription="@string/mr_button_content_description"
style="@style/TitleBarButton" />
</LinearLayout>
@@ -120,6 +121,7 @@
<SeekBar
android:id="@+id/mediacontroller_progress"
+ android:contentDescription="@string/mcv2_seek_bar_desc"
android:layout_width="match_parent"
android:layout_height="12dp"
android:maxHeight="2dp"
@@ -233,4 +235,4 @@
</LinearLayout>
</LinearLayout>
</RelativeLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/MediaComponents/res/values/strings.xml b/packages/MediaComponents/res/values/strings.xml
index 69e9dff..aaceac8 100644
--- a/packages/MediaComponents/res/values/strings.xml
+++ b/packages/MediaComponents/res/values/strings.xml
@@ -84,10 +84,6 @@
<!-- Placeholder text indicating that the user is currently casting screen. [CHAR LIMIT=50] -->
<string name="mr_controller_casting_screen">Casting screen</string>
- <string name="lockscreen_pause_button_content_description">Pause</string>
- <string name="lockscreen_play_button_content_description">Play</string>
- <string name="lockscreen_replay_button_content_description">Replay</string>
-
<!-- Text for error alert when a video container is not valid for progressive download/playback. -->
<string name="VideoView2_error_text_invalid_progressive_playback">This video isn\'t valid for streaming to this device.</string>
<!-- Text for error alert when a video cannot be played. It can be used by any app. -->
@@ -133,4 +129,25 @@
<string name="MediaControlView2_audio_track_number_text">
Track <xliff:g id="audio_number" example="1">%1$s</xliff:g>
</string>
+
+ <!--Content Descriptions -->
+ <string name="mcv2_back_button_desc">Back</string>
+ <string name="mcv2_overflow_left_button_desc">See more buttons</string>
+ <string name="mcv2_overflow_right_button_desc">Back to previous button list</string>
+ <string name="mcv2_seek_bar_desc">Playback progress</string>
+ <string name="mcv2_settings_button_desc">Settings</string>
+ <string name="mcv2_video_quality_button_desc">Video Quality Selection</string>
+ <string name="mcv2_cc_is_on">Subtitle is on. Click to hide it.</string>
+ <string name="mcv2_cc_is_off">Subtitle is off. Click to show it.</string>
+ <string name="mcv2_replay_button_desc">Replay</string>
+ <string name="mcv2_play_button_desc">Play</string>
+ <string name="mcv2_pause_button_desc">Pause</string>
+ <string name="mcv2_previous_button_desc">Previous media</string>
+ <string name="mcv2_next_button_desc">Next media</string>
+ <string name="mcv2_rewind_button_desc">Rewind by 10 seconds</string>
+ <string name="mcv2_ffwd_button_desc">Go forward by 30 seconds</string>
+ <string name="mcv2_launch_button_desc">Launch Link</string>
+ <string name="mcv2_muted_button_desc">Muted. Click to unmute</string>
+ <string name="mcv2_unmuted_button_desc">Click to Mute</string>
+ <string name="mcv2_full_screen_button_desc">Full screen</string>
</resources>
diff --git a/packages/MediaComponents/res/values/style.xml b/packages/MediaComponents/res/values/style.xml
index b1da137..0be04e6 100644
--- a/packages/MediaComponents/res/values/style.xml
+++ b/packages/MediaComponents/res/values/style.xml
@@ -10,30 +10,35 @@
<item name="android:src">@drawable/ic_skip_previous</item>
<item name="android:layout_width">@dimen/mcv2_full_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_full_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_previous_button_desc</item>
</style>
<style name="FullTransportControlsButton.Next">
<item name="android:src">@drawable/ic_skip_next</item>
<item name="android:layout_width">@dimen/mcv2_full_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_full_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_next_button_desc</item>
</style>
<style name="FullTransportControlsButton.Pause">
<item name="android:src">@drawable/ic_pause_circle_filled</item>
<item name="android:layout_width">@dimen/mcv2_pause_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_pause_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_pause_button_desc</item>
</style>
<style name="FullTransportControlsButton.Ffwd">
<item name="android:src">@drawable/ic_forward_30</item>
<item name="android:layout_width">@dimen/mcv2_full_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_full_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_ffwd_button_desc</item>
</style>
<style name="FullTransportControlsButton.Rew">
<item name="android:src">@drawable/ic_rewind_10</item>
<item name="android:layout_width">@dimen/mcv2_full_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_full_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_rewind_button_desc</item>
</style>
<style name="EmbeddedTransportControlsButton">
@@ -46,30 +51,35 @@
<item name="android:src">@drawable/ic_skip_previous</item>
<item name="android:layout_width">@dimen/mcv2_embedded_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_previous_button_desc</item>
</style>
<style name="EmbeddedTransportControlsButton.Next">
<item name="android:src">@drawable/ic_skip_next</item>
<item name="android:layout_width">@dimen/mcv2_embedded_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_next_button_desc</item>
</style>
<style name="EmbeddedTransportControlsButton.Pause">
<item name="android:src">@drawable/ic_pause_circle_filled</item>
<item name="android:layout_width">@dimen/mcv2_pause_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_pause_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_pause_button_desc</item>
</style>
<style name="EmbeddedTransportControlsButton.Ffwd">
<item name="android:src">@drawable/ic_forward_30</item>
<item name="android:layout_width">@dimen/mcv2_embedded_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_ffwd_button_desc</item>
</style>
<style name="EmbeddedTransportControlsButton.Rew">
<item name="android:src">@drawable/ic_rewind_10</item>
<item name="android:layout_width">@dimen/mcv2_embedded_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_embedded_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_rewind_button_desc</item>
</style>
<style name="MinimalTransportControlsButton">
@@ -81,6 +91,7 @@
<item name="android:src">@drawable/ic_pause_circle_filled</item>
<item name="android:layout_width">@dimen/mcv2_minimal_icon_size</item>
<item name="android:layout_height">@dimen/mcv2_minimal_icon_size</item>
+ <item name="android:contentDescription">@string/mcv2_pause_button_desc</item>
</style>
<style name="TitleBar">
@@ -95,10 +106,12 @@
<style name="TitleBarButton.Back">
<item name="android:src">@drawable/ic_arrow_back</item>
+ <item name="android:contentDescription">@string/mcv2_back_button_desc</item>
</style>
<style name="TitleBarButton.Launch">
<item name="android:src">@drawable/ic_launch</item>
+ <item name="android:contentDescription">@string/mcv2_launch_button_desc</item>
</style>
<style name="TimeText">
@@ -137,29 +150,36 @@
<style name="BottomBarButton.CC">
<item name="android:src">@drawable/ic_subtitle_off</item>
+ <item name="android:contentDescription">@string/mcv2_cc_is_off</item>
</style>
<style name="BottomBarButton.FullScreen">
<item name="android:src">@drawable/ic_fullscreen</item>
+ <item name="android:contentDescription">@string/mcv2_full_screen_button_desc</item>
</style>
<style name="BottomBarButton.OverflowRight">
<item name="android:src">@drawable/ic_chevron_right</item>
+ <item name="android:contentDescription">@string/mcv2_overflow_right_button_desc</item>
</style>
<style name="BottomBarButton.OverflowLeft">
<item name="android:src">@drawable/ic_chevron_left</item>
+ <item name="android:contentDescription">@string/mcv2_overflow_left_button_desc</item>
</style>
<style name="BottomBarButton.Settings">
<item name="android:src">@drawable/ic_settings</item>
+ <item name="android:contentDescription">@string/mcv2_settings_button_desc</item>
</style>
<style name="BottomBarButton.Mute">
<item name="android:src">@drawable/ic_unmute</item>
+ <item name="android:contentDescription">@string/mcv2_unmuted_button_desc</item>
</style>
<style name="BottomBarButton.VideoQuality">
- <item name="android:src">@drawable/ic_high_quality</item>
+ <item name="android:src">@drawable/ic_high_quality</item>
+ <item name="android:contentDescription">@string/mcv2_video_quality_button_desc</item>
</style>
</resources>
diff --git a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
index 0091816..721e0a2 100644
--- a/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaController2Impl.java
@@ -24,12 +24,12 @@
import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA;
import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE;
import static android.media.MediaSession2.COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE;
-import static android.media.MediaSession2.COMMAND_CODE_PLAY_FROM_MEDIA_ID;
-import static android.media.MediaSession2.COMMAND_CODE_PLAY_FROM_SEARCH;
-import static android.media.MediaSession2.COMMAND_CODE_PLAY_FROM_URI;
-import static android.media.MediaSession2.COMMAND_CODE_PREPARE_FROM_MEDIA_ID;
-import static android.media.MediaSession2.COMMAND_CODE_PREPARE_FROM_SEARCH;
-import static android.media.MediaSession2.COMMAND_CODE_PREPARE_FROM_URI;
+import static android.media.MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID;
+import static android.media.MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH;
+import static android.media.MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_URI;
+import static android.media.MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID;
+import static android.media.MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH;
+import static android.media.MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_URI;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -438,7 +438,7 @@
@Override
public void prepareFromUri_impl(Uri uri, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PREPARE_FROM_URI);
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PREPARE_FROM_URI);
if (uri == null) {
throw new IllegalArgumentException("uri shouldn't be null");
}
@@ -455,7 +455,8 @@
@Override
public void prepareFromSearch_impl(String query, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PREPARE_FROM_SEARCH);
+ final IMediaSession2 binder = getSessionBinderIfAble(
+ COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH);
if (TextUtils.isEmpty(query)) {
throw new IllegalArgumentException("query shouldn't be empty");
}
@@ -472,7 +473,8 @@
@Override
public void prepareFromMediaId_impl(String mediaId, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PREPARE_FROM_MEDIA_ID);
+ final IMediaSession2 binder = getSessionBinderIfAble(
+ COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID);
if (mediaId == null) {
throw new IllegalArgumentException("mediaId shouldn't be null");
}
@@ -489,7 +491,7 @@
@Override
public void playFromUri_impl(Uri uri, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAY_FROM_URI);
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PLAY_FROM_URI);
if (uri == null) {
throw new IllegalArgumentException("uri shouldn't be null");
}
@@ -506,7 +508,7 @@
@Override
public void playFromSearch_impl(String query, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAY_FROM_SEARCH);
+ final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PLAY_FROM_SEARCH);
if (TextUtils.isEmpty(query)) {
throw new IllegalArgumentException("query shouldn't be empty");
}
@@ -523,7 +525,8 @@
@Override
public void playFromMediaId_impl(String mediaId, Bundle extras) {
- final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAY_FROM_MEDIA_ID);
+ final IMediaSession2 binder = getSessionBinderIfAble(
+ COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID);
if (mediaId == null) {
throw new IllegalArgumentException("mediaId shouldn't be null");
}
@@ -764,7 +767,7 @@
}
@Override
- public long getPosition_impl() {
+ public long getCurrentPosition_impl() {
synchronized (mLock) {
long timeDiff = System.currentTimeMillis() - mPositionEventTimeMs;
long expectedPosition = mPositionMs + (long) (mPlaybackSpeed * timeDiff);
@@ -837,7 +840,8 @@
if (!mInstance.isConnected()) {
return;
}
- mCallback.onBufferedPositionChanged(mInstance, bufferedPositionMs);
+ // TODO(jaewan): Fix this -- it's now buffered state
+ //mCallback.onBufferedPositionChanged(mInstance, bufferedPositionMs);
});
}
@@ -862,8 +866,7 @@
if (!mInstance.isConnected()) {
return;
}
- // TODO(jaewan): Fix public API not to take playlistAgent.
- mCallback.onPlaylistChanged(mInstance, null, playlist, metadata);
+ mCallback.onPlaylistChanged(mInstance, playlist, metadata);
});
}
@@ -875,8 +878,7 @@
if (!mInstance.isConnected()) {
return;
}
- // TODO(jaewan): Fix public API not to take playlistAgent.
- mCallback.onPlaylistMetadataChanged(mInstance, null, metadata);
+ mCallback.onPlaylistMetadataChanged(mInstance, metadata);
});
}
@@ -888,8 +890,7 @@
if (!mInstance.isConnected()) {
return;
}
- // TODO(jaewan): Fix public API not to take playlistAgent.
- mCallback.onShuffleModeChanged(mInstance, null, shuffleMode);
+ mCallback.onShuffleModeChanged(mInstance, shuffleMode);
});
}
@@ -901,8 +902,7 @@
if (!mInstance.isConnected()) {
return;
}
- // TODO(jaewan): Fix public API not to take playlistAgent.
- mCallback.onRepeatModeChanged(mInstance, null, repeatMode);
+ mCallback.onRepeatModeChanged(mInstance, repeatMode);
});
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java b/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
index 286f5ee..5fd5812 100644
--- a/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaMetadata2Impl.java
@@ -78,8 +78,6 @@
METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
METADATA_KEYS_TYPE.put(METADATA_KEY_ADVERTISEMENT, METADATA_TYPE_LONG);
METADATA_KEYS_TYPE.put(METADATA_KEY_DOWNLOAD_STATUS, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_RADIO_FREQUENCY, METADATA_TYPE_FLOAT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_RADIO_CALLSIGN, METADATA_TYPE_TEXT);
}
private static final @TextKey
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
index 2b7c72a..2d04765 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Impl.java
@@ -48,6 +48,7 @@
import android.media.MediaSession2.CommandButton;
import android.media.MediaSession2.CommandGroup;
import android.media.MediaSession2.ControllerInfo;
+import android.media.MediaSession2.OnDataSourceMissingHelper;
import android.media.MediaSession2.SessionCallback;
import android.media.MediaSessionService2;
import android.media.SessionToken2;
@@ -61,15 +62,16 @@
import android.os.ResultReceiver;
import android.support.annotation.GuardedBy;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Log;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Set;
import java.util.concurrent.Executor;
public class MediaSession2Impl implements MediaSession2Provider {
@@ -111,9 +113,13 @@
@GuardedBy("mLock")
private MediaPlaylistAgent mPlaylistAgent;
@GuardedBy("mLock")
+ private SessionPlaylistAgent mSessionPlaylistAgent;
+ @GuardedBy("mLock")
private VolumeProvider2 mVolumeProvider;
@GuardedBy("mLock")
private PlaybackInfo mPlaybackInfo;
+ @GuardedBy("mLock")
+ private OnDataSourceMissingHelper mDsmHelper;
/**
* Can be only called by the {@link Builder#build()}.
@@ -207,7 +213,7 @@
}
@Override
- public void updatePlayer_impl(MediaPlayerBase player, MediaPlaylistAgent playlistAgent,
+ public void updatePlayer_impl(@NonNull MediaPlayerBase player, MediaPlaylistAgent playlistAgent,
VolumeProvider2 volumeProvider) throws IllegalArgumentException {
ensureCallingThread();
if (player == null) {
@@ -225,9 +231,12 @@
oldPlayer = mPlayer;
oldAgent = mPlaylistAgent;
mPlayer = player;
- // TODO(jaewan): Replace this with the proper default agent (b/74090741)
if (agent == null) {
- agent = new MediaPlaylistAgent(mContext) {};
+ mSessionPlaylistAgent = new SessionPlaylistAgent(mContext, this, mPlayer);
+ if (mDsmHelper != null) {
+ mSessionPlaylistAgent.setOnDataSourceMissingHelper(mDsmHelper);
+ }
+ agent = mSessionPlaylistAgent;
}
mPlaylistAgent = agent;
mVolumeProvider = volumeProvider;
@@ -312,6 +321,7 @@
mPlayer = null;
agent = mPlaylistAgent;
mPlaylistAgent = null;
+ mSessionPlaylistAgent = null;
}
if (player != null) {
player.unregisterPlayerEventCallback(mPlayerEventCallback);
@@ -385,7 +395,7 @@
}
@Override
- public void skipToPlaylistItem_impl(MediaItem2 item) {
+ public void skipToPlaylistItem_impl(@NonNull MediaItem2 item) {
if (item == null) {
throw new IllegalArgumentException("item shouldn't be null");
}
@@ -418,7 +428,8 @@
}
@Override
- public void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout) {
+ public void setCustomLayout_impl(@NonNull ControllerInfo controller,
+ @NonNull List<CommandButton> layout) {
ensureCallingThread();
if (controller == null) {
throw new IllegalArgumentException("controller shouldn't be null");
@@ -434,7 +445,8 @@
//////////////////////////////////////////////////////////////////////////////////////
@Override
- public void setAllowedCommands_impl(ControllerInfo controller, CommandGroup commands) {
+ public void setAllowedCommands_impl(@NonNull ControllerInfo controller,
+ @NonNull CommandGroup commands) {
if (controller == null) {
throw new IllegalArgumentException("controller shouldn't be null");
}
@@ -445,8 +457,8 @@
}
@Override
- public void sendCustomCommand_impl(ControllerInfo controller, Command command, Bundle args,
- ResultReceiver receiver) {
+ public void sendCustomCommand_impl(@NonNull ControllerInfo controller, @NonNull Command command,
+ Bundle args, ResultReceiver receiver) {
if (controller == null) {
throw new IllegalArgumentException("controller shouldn't be null");
}
@@ -457,7 +469,7 @@
}
@Override
- public void sendCustomCommand_impl(Command command, Bundle args) {
+ public void sendCustomCommand_impl(@NonNull Command command, Bundle args) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -465,7 +477,7 @@
}
@Override
- public void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata) {
+ public void setPlaylist_impl(@NonNull List<MediaItem2> list, MediaMetadata2 metadata) {
if (list == null) {
throw new IllegalArgumentException("list shouldn't be null");
}
@@ -489,7 +501,7 @@
}
@Override
- public void addPlaylistItem_impl(int index, MediaItem2 item) {
+ public void addPlaylistItem_impl(int index, @NonNull MediaItem2 item) {
if (index < 0) {
throw new IllegalArgumentException("index shouldn't be negative");
}
@@ -505,7 +517,7 @@
}
@Override
- public void removePlaylistItem_impl(MediaItem2 item) {
+ public void removePlaylistItem_impl(@NonNull MediaItem2 item) {
if (item == null) {
throw new IllegalArgumentException("item shouldn't be null");
}
@@ -518,7 +530,7 @@
}
@Override
- public void replacePlaylistItem_impl(int index, MediaItem2 item) {
+ public void replacePlaylistItem_impl(int index, @NonNull MediaItem2 item) {
if (index < 0) {
throw new IllegalArgumentException("index shouldn't be negative");
}
@@ -659,7 +671,7 @@
}
@Override
- public long getPosition_impl() {
+ public long getCurrentPosition_impl() {
final MediaPlayerBase player = mPlayer;
if (player != null) {
return mPlayer.getCurrentPosition();
@@ -685,6 +697,29 @@
mSessionStub.notifyError(errorCode, extras);
}
+ @Override
+ public void setOnDataSourceMissingHelper_impl(@NonNull OnDataSourceMissingHelper helper) {
+ if (helper == null) {
+ throw new IllegalArgumentException("helper shouldn't be null");
+ }
+ synchronized (mLock) {
+ mDsmHelper = helper;
+ if (mSessionPlaylistAgent != null) {
+ mSessionPlaylistAgent.setOnDataSourceMissingHelper(helper);
+ }
+ }
+ }
+
+ @Override
+ public void clearOnDataSourceMissingHelper_impl() {
+ synchronized (mLock) {
+ mDsmHelper = null;
+ if (mSessionPlaylistAgent != null) {
+ mSessionPlaylistAgent.clearOnDataSourceMissingHelper();
+ }
+ }
+ }
+
///////////////////////////////////////////////////
// Protected or private methods
///////////////////////////////////////////////////
@@ -1022,7 +1057,7 @@
/**
* @return a new Command instance from the Bundle
*/
- public static Command fromBundle_impl(Context context, Bundle command) {
+ public static Command fromBundle_impl(Context context, @NonNull Bundle command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -1044,8 +1079,7 @@
return false;
}
CommandImpl other = (CommandImpl) obj;
- // TODO(jaewan): Should we also compare contents in bundle?
- // It may not be possible if the bundle contains private class.
+ // TODO(jaewan): Compare Commands with the generated UUID, as we're doing for the MI2.
return mCommandCode == other.mCommandCode
&& TextUtils.equals(mCustomCommand, other.mCustomCommand);
}
@@ -1074,7 +1108,7 @@
// Prefix for command codes that will be sent directly to the MediaPlaylistAgent
private static final String PREFIX_COMMAND_CODE_PLAYLIST = "COMMAND_CODE_PLAYLIST_";
- private List<Command> mCommands = new ArrayList<>();
+ private Set<Command> mCommands = new HashSet<>();
private final Context mContext;
private final CommandGroup mInstance;
@@ -1092,7 +1126,7 @@
}
@Override
- public void addCommand_impl(Command command) {
+ public void addCommand_impl(@NonNull Command command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -1129,7 +1163,7 @@
}
@Override
- public void removeCommand_impl(Command command) {
+ public void removeCommand_impl(@NonNull Command command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -1137,7 +1171,7 @@
}
@Override
- public boolean hasCommand_impl(Command command) {
+ public boolean hasCommand_impl(@NonNull Command command) {
if (command == null) {
throw new IllegalArgumentException("command shouldn't be null");
}
@@ -1149,8 +1183,8 @@
if (code == COMMAND_CODE_CUSTOM) {
throw new IllegalArgumentException("Use hasCommand(Command) for custom command");
}
- for (int i = 0; i < mCommands.size(); i++) {
- if (mCommands.get(i).getCommandCode() == code) {
+ for (Command command : mCommands) {
+ if (command.getCommandCode() == code) {
return true;
}
}
@@ -1158,12 +1192,12 @@
}
@Override
- public List<Command> getCommands_impl() {
+ public Set<Command> getCommands_impl() {
return getCommands();
}
- public List<Command> getCommands() {
- return Collections.unmodifiableList(mCommands);
+ public Set<Command> getCommands() {
+ return Collections.unmodifiableSet(mCommands);
}
/**
@@ -1173,8 +1207,8 @@
@Override
public Bundle toBundle_impl() {
ArrayList<Bundle> list = new ArrayList<>();
- for (int i = 0; i < mCommands.size(); i++) {
- list.add(mCommands.get(i).toBundle());
+ for (Command command : mCommands) {
+ list.add(command.toBundle());
}
Bundle bundle = new Bundle();
bundle.putParcelableArrayList(KEY_COMMANDS, list);
@@ -1217,7 +1251,7 @@
private final IMediaController2 mControllerBinder;
public ControllerInfoImpl(Context context, ControllerInfo instance, int uid,
- int pid, String packageName, IMediaController2 callback) {
+ int pid, @NonNull String packageName, @NonNull IMediaController2 callback) {
if (TextUtils.isEmpty(packageName)) {
throw new IllegalArgumentException("packageName shouldn't be empty");
}
@@ -1234,7 +1268,7 @@
// Ask server whether the controller is trusted.
// App cannot know this because apps cannot query enabled notification listener for
// another package, but system server can do.
- mIsTrusted = manager.isTrusted(uid, packageName);
+ mIsTrusted = manager.isTrusted(packageName, pid, uid);
}
@Override
@@ -1468,7 +1502,7 @@
* {@link MediaSession2} or {@link MediaController2}.
*/
// TODO(jaewan): Also need executor
- public BuilderBaseImpl(Context context) {
+ public BuilderBaseImpl(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("context shouldn't be null");
}
@@ -1478,7 +1512,7 @@
}
@Override
- public void setPlayer_impl(MediaPlayerBase player) {
+ public void setPlayer_impl(@NonNull MediaPlayerBase player) {
if (player == null) {
throw new IllegalArgumentException("player shouldn't be null");
}
@@ -1486,7 +1520,7 @@
}
@Override
- public void setPlaylistAgent_impl(MediaPlaylistAgent playlistAgent) {
+ public void setPlaylistAgent_impl(@NonNull MediaPlaylistAgent playlistAgent) {
if (playlistAgent == null) {
throw new IllegalArgumentException("playlistAgent shouldn't be null");
}
@@ -1504,7 +1538,7 @@
}
@Override
- public void setId_impl(String id) {
+ public void setId_impl(@NonNull String id) {
if (id == null) {
throw new IllegalArgumentException("id shouldn't be null");
}
@@ -1512,7 +1546,7 @@
}
@Override
- public void setSessionCallback_impl(Executor executor, C callback) {
+ public void setSessionCallback_impl(@NonNull Executor executor, @NonNull C callback) {
if (executor == null) {
throw new IllegalArgumentException("executor shouldn't be null");
}
diff --git a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
index caf834a..a3cb0c6 100644
--- a/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
+++ b/packages/MediaComponents/src/com/android/media/MediaSession2Stub.java
@@ -86,9 +86,8 @@
CommandGroupImpl group = new CommandGroupImpl(session.getContext());
group.addAllPlaybackCommands();
group.addAllPlaylistCommands();
- List<Command> commands = group.getCommands();
- for (int i = 0; i < commands.size(); i++) {
- Command command = commands.get(i);
+ Set<Command> commands = group.getCommands();
+ for (Command command : commands) {
sCommandsForOnCommandRequest.append(command.getCommandCode(), command);
}
}
@@ -389,7 +388,7 @@
// use thread poll for incoming calls.
final int playerState = session.getInstance().getPlayerState();
final long positionEventTimeMs = System.currentTimeMillis();
- final long positionMs = session.getInstance().getPosition();
+ final long positionMs = session.getInstance().getCurrentPosition();
final float playbackSpeed = session.getInstance().getPlaybackSpeed();
final long bufferedPositionMs = session.getInstance().getBufferedPosition();
final Bundle playbackInfoBundle = ((MediaController2Impl.PlaybackInfoImpl)
@@ -540,7 +539,7 @@
@Override
public void prepareFromUri(final IMediaController2 caller, final Uri uri,
final Bundle extras) {
- onCommand(caller, MediaSession2.COMMAND_CODE_PREPARE_FROM_URI, (session, controller) -> {
+ onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_URI, (session, controller) -> {
if (uri == null) {
Log.w(TAG, "prepareFromUri(): Ignoring null uri from " + controller);
return;
@@ -552,7 +551,7 @@
@Override
public void prepareFromSearch(final IMediaController2 caller, final String query,
final Bundle extras) {
- onCommand(caller, MediaSession2.COMMAND_CODE_PREPARE_FROM_SEARCH, (session, controller) -> {
+ onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH, (session, controller) -> {
if (TextUtils.isEmpty(query)) {
Log.w(TAG, "prepareFromSearch(): Ignoring empty query from " + controller);
return;
@@ -565,7 +564,7 @@
@Override
public void prepareFromMediaId(final IMediaController2 caller, final String mediaId,
final Bundle extras) {
- onCommand(caller, MediaSession2.COMMAND_CODE_PREPARE_FROM_MEDIA_ID,
+ onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID,
(session, controller) -> {
if (mediaId == null) {
Log.w(TAG, "prepareFromMediaId(): Ignoring null mediaId from " + controller);
@@ -579,7 +578,7 @@
@Override
public void playFromUri(final IMediaController2 caller, final Uri uri,
final Bundle extras) {
- onCommand(caller, MediaSession2.COMMAND_CODE_PLAY_FROM_URI, (session, controller) -> {
+ onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_URI, (session, controller) -> {
if (uri == null) {
Log.w(TAG, "playFromUri(): Ignoring null uri from " + controller);
return;
@@ -591,7 +590,7 @@
@Override
public void playFromSearch(final IMediaController2 caller, final String query,
final Bundle extras) {
- onCommand(caller, MediaSession2.COMMAND_CODE_PLAY_FROM_SEARCH, (session, controller) -> {
+ onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH, (session, controller) -> {
if (TextUtils.isEmpty(query)) {
Log.w(TAG, "playFromSearch(): Ignoring empty query from " + controller);
return;
@@ -604,7 +603,7 @@
@Override
public void playFromMediaId(final IMediaController2 caller, final String mediaId,
final Bundle extras) {
- onCommand(caller, MediaSession2.COMMAND_CODE_PLAY_FROM_MEDIA_ID, (session, controller) -> {
+ onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID, (session, controller) -> {
if (mediaId == null) {
Log.w(TAG, "playFromMediaId(): Ignoring null mediaId from " + controller);
return;
@@ -617,8 +616,7 @@
@Override
public void setRating(final IMediaController2 caller, final String mediaId,
final Bundle ratingBundle) {
- // TODO(jaewan): Define COMMAND_CODE_SET_RATING
- onCommand(caller, MediaSession2.COMMAND_CODE_SET_RATING, (session, controller) -> {
+ onCommand(caller, MediaSession2.COMMAND_CODE_SESSION_SET_RATING, (session, controller) -> {
if (mediaId == null) {
Log.w(TAG, "setRating(): Ignoring null mediaId from " + controller);
return;
@@ -717,7 +715,7 @@
@Override
public void skipToPreviousItem(IMediaController2 caller) {
- onCommand(caller, MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_PREV_ITEM,
+ onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM,
(session, controller) -> {
session.getInstance().skipToPreviousItem();
});
@@ -725,7 +723,7 @@
@Override
public void skipToNextItem(IMediaController2 caller) {
- onCommand(caller, MediaSession2.COMMAND_CODE_PLAYBACK_SKIP_NEXT_ITEM,
+ onCommand(caller, MediaSession2.COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM,
(session, controller) -> {
session.getInstance().skipToNextItem();
});
diff --git a/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java b/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
index 6805dad..dfbe56a 100644
--- a/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
+++ b/packages/MediaComponents/src/com/android/media/SessionPlaylistAgent.java
@@ -23,8 +23,8 @@
import android.media.MediaItem2;
import android.media.MediaMetadata2;
import android.media.MediaPlayerBase;
+import android.media.MediaPlayerBase.PlayerEventCallback;
import android.media.MediaPlaylistAgent;
-import android.media.MediaSession2;
import android.media.MediaSession2.OnDataSourceMissingHelper;
import android.util.ArrayMap;
@@ -47,14 +47,13 @@
private final PlayItem mEopPlayItem = new PlayItem(END_OF_PLAYLIST, null);
private final Object mLock = new Object();
- private final MediaSession2 mSession;
+ private final MediaSession2Impl mSessionImpl;
+ private final MyPlayerEventCallback mPlayerCallback;
- // TODO: Set data sources properly into mPlayer (b/74090741)
@GuardedBy("mLock")
private MediaPlayerBase mPlayer;
@GuardedBy("mLock")
- private OnDataSourceMissingHelper mDsdHelper;
-
+ private OnDataSourceMissingHelper mDsmHelper;
// TODO: Check if having the same item is okay (b/74090741)
@GuardedBy("mLock")
private ArrayList<MediaItem2> mPlaylist = new ArrayList<>();
@@ -71,6 +70,22 @@
@GuardedBy("mLock")
private PlayItem mCurrent;
+ // Called on session callback executor.
+ private class MyPlayerEventCallback extends PlayerEventCallback {
+ public void onCurrentDataSourceChanged(@NonNull MediaPlayerBase mpb,
+ @Nullable DataSourceDesc dsd) {
+ if (mPlayer != mpb) {
+ return;
+ }
+ synchronized (mLock) {
+ if (dsd == null && mCurrent != null) {
+ mCurrent = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1);
+ updateCurrentIfNeededLocked();
+ }
+ }
+ }
+ }
+
private class PlayItem {
int shuffledIdx;
DataSourceDesc dsd;
@@ -118,31 +133,46 @@
}
}
- public SessionPlaylistAgent(@NonNull Context context, @NonNull MediaSession2 session,
+ public SessionPlaylistAgent(@NonNull Context context, @NonNull MediaSession2Impl sessionImpl,
@NonNull MediaPlayerBase player) {
super(context);
- if (session == null) {
- throw new IllegalArgumentException("session shouldn't be null");
+ if (sessionImpl == null) {
+ throw new IllegalArgumentException("sessionImpl shouldn't be null");
}
if (player == null) {
throw new IllegalArgumentException("player shouldn't be null");
}
- mSession = session;
+ mSessionImpl = sessionImpl;
mPlayer = player;
+ mPlayerCallback = new MyPlayerEventCallback();
+ mPlayer.registerPlayerEventCallback(mSessionImpl.getCallbackExecutor(), mPlayerCallback);
}
- public void setPlayer(MediaPlayerBase player) {
+ public void setPlayer(@NonNull MediaPlayerBase player) {
if (player == null) {
throw new IllegalArgumentException("player shouldn't be null");
}
synchronized (mLock) {
+ if (player == mPlayer) {
+ return;
+ }
+ mPlayer.unregisterPlayerEventCallback(mPlayerCallback);
mPlayer = player;
+ mPlayer.registerPlayerEventCallback(
+ mSessionImpl.getCallbackExecutor(), mPlayerCallback);
+ updatePlayerDataSourceLocked();
}
}
public void setOnDataSourceMissingHelper(OnDataSourceMissingHelper helper) {
synchronized (mLock) {
- mDsdHelper = helper;
+ mDsmHelper = helper;
+ }
+ }
+
+ public void clearOnDataSourceMissingHelper() {
+ synchronized (mLock) {
+ mDsmHelper = null;
}
}
@@ -154,8 +184,7 @@
}
@Override
- public void setPlaylist(@NonNull List<MediaItem2> list,
- @Nullable MediaMetadata2 metadata) {
+ public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
if (list == null) {
throw new IllegalArgumentException("list shouldn't be null");
}
@@ -169,6 +198,7 @@
mMetadata = metadata;
mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
+ updatePlayerDataSourceLocked();
}
notifyPlaylistChanged();
}
@@ -207,6 +237,7 @@
}
if (!hasValidItem()) {
mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
+ updatePlayerDataSourceLocked();
} else {
updateCurrentIfNeededLocked();
}
@@ -246,6 +277,7 @@
mPlaylist.set(index, item);
if (!hasValidItem()) {
mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
+ updatePlayerDataSourceLocked();
} else {
updateCurrentIfNeededLocked();
}
@@ -288,7 +320,7 @@
@Override
public void skipToNextItem() {
synchronized (mLock) {
- if (!hasValidItem()) {
+ if (!hasValidItem() || mCurrent == mEopPlayItem) {
return;
}
PlayItem next = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1);
@@ -315,6 +347,23 @@
return;
}
mRepeatMode = repeatMode;
+ switch (repeatMode) {
+ case MediaPlaylistAgent.REPEAT_MODE_ONE:
+ if (mCurrent != null && mCurrent != mEopPlayItem) {
+ mPlayer.loopCurrent(true);
+ }
+ break;
+ case MediaPlaylistAgent.REPEAT_MODE_ALL:
+ case MediaPlaylistAgent.REPEAT_MODE_GROUP:
+ if (mCurrent == mEopPlayItem) {
+ mCurrent = getNextValidPlayItemLocked(END_OF_PLAYLIST, 1);
+ updatePlayerDataSourceLocked();
+ }
+ // pass through
+ case MediaPlaylistAgent.REPEAT_MODE_NONE:
+ mPlayer.loopCurrent(false);
+ break;
+ }
}
notifyRepeatModeChanged();
}
@@ -336,6 +385,7 @@
}
mShuffleMode = shuffleMode;
applyShuffleModeLocked();
+ updateCurrentIfNeededLocked();
}
notifyShuffleModeChanged();
}
@@ -359,10 +409,10 @@
if (dsd != null) {
return dsd;
}
- OnDataSourceMissingHelper helper = mDsdHelper;
+ OnDataSourceMissingHelper helper = mDsmHelper;
if (helper != null) {
// TODO: Do not call onDataSourceMissing with the lock (b/74090741).
- dsd = helper.onDataSourceMissing(mSession, item);
+ dsd = helper.onDataSourceMissing(mSessionImpl.getInstance(), item);
if (dsd != null) {
mItemDsdMap.put(item, dsd);
}
@@ -370,6 +420,7 @@
return dsd;
}
+ // TODO: consider to call updateCurrentIfNeededLocked inside (b/74090741)
private PlayItem getNextValidPlayItemLocked(int curShuffledIdx, int direction) {
int size = mPlaylist.size();
if (curShuffledIdx == END_OF_PLAYLIST) {
@@ -411,9 +462,21 @@
mCurrent = getNextValidPlayItemLocked(mCurrent.shuffledIdx, 1);
}
}
+ updatePlayerDataSourceLocked();
return;
}
+ private void updatePlayerDataSourceLocked() {
+ if (mCurrent == null || mCurrent == mEopPlayItem) {
+ return;
+ }
+ if (mPlayer.getCurrentDataSource() != mCurrent.dsd) {
+ mPlayer.setDataSource(mCurrent.dsd);
+ mPlayer.loopCurrent(mRepeatMode == MediaPlaylistAgent.REPEAT_MODE_ONE);
+ }
+ // TODO: Call setNextDataSource (b/74090741)
+ }
+
private void applyShuffleModeLocked() {
mShuffledList.clear();
mShuffledList.addAll(mPlaylist);
diff --git a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
index 9ae75b0..4cdc41d 100644
--- a/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/MediaControlView2Impl.java
@@ -207,10 +207,6 @@
private List<String> mPlaybackSpeedTextList;
private List<Float> mPlaybackSpeedList;
- private CharSequence mPlayDescription;
- private CharSequence mPauseDescription;
- private CharSequence mReplayDescription;
-
public MediaControlView2Impl(MediaControlView2 instance,
ViewGroupProvider superProvider, ViewGroupProvider privateProvider) {
super(instance, superProvider, privateProvider);
@@ -479,12 +475,6 @@
}
private void initControllerView(View v) {
- mPlayDescription = mResources.getText(R.string.lockscreen_play_button_content_description);
- mPauseDescription =
- mResources.getText(R.string.lockscreen_pause_button_content_description);
- mReplayDescription =
- mResources.getText(R.string.lockscreen_replay_button_content_description);
-
// Relating to Title Bar View
mTitleBar = v.findViewById(R.id.title_bar);
mTitleView = v.findViewById(R.id.title_text);
@@ -707,12 +697,14 @@
mControls.pause();
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_play_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPlayDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_play_button_desc));
} else {
mControls.play();
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_pause_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPauseDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_pause_button_desc));
}
}
@@ -748,7 +740,8 @@
if (mIsStopped) {
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_play_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPlayDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_play_button_desc));
mIsStopped = false;
}
}
@@ -897,11 +890,15 @@
if (!mIsMute) {
mMuteButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_mute, null));
+ mMuteButton.setContentDescription(
+ mResources.getString(R.string.mcv2_muted_button_desc));
mIsMute = true;
mController.sendCommand(COMMAND_MUTE, null, null);
} else {
mMuteButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_unmute, null));
+ mMuteButton.setContentDescription(
+ mResources.getString(R.string.mcv2_unmuted_button_desc));
mIsMute = false;
mController.sendCommand(COMMAND_UNMUTE, null, null);
}
@@ -975,12 +972,16 @@
MediaControlView2Impl.COMMAND_SHOW_SUBTITLE, extra, null);
mSubtitleButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_subtitle_on, null));
+ mSubtitleButton.setContentDescription(
+ mResources.getString(R.string.mcv2_cc_is_on));
mSubtitleIsEnabled = true;
} else {
mController.sendCommand(
MediaControlView2Impl.COMMAND_HIDE_SUBTITLE, null, null);
mSubtitleButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_subtitle_off, null));
+ mSubtitleButton.setContentDescription(
+ mResources.getString(R.string.mcv2_cc_is_off));
mSubtitleIsEnabled = false;
}
@@ -1106,11 +1107,13 @@
if (isPlaying()) {
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_pause_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPauseDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_pause_button_desc));
} else {
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_play_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPlayDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_play_button_desc));
}
}
@@ -1218,19 +1221,22 @@
case PlaybackState.STATE_PLAYING:
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_pause_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPauseDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_pause_button_desc));
mInstance.removeCallbacks(mUpdateProgress);
mInstance.post(mUpdateProgress);
break;
case PlaybackState.STATE_PAUSED:
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_play_circle_filled, null));
- mPlayPauseButton.setContentDescription(mPlayDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_play_button_desc));
break;
case PlaybackState.STATE_STOPPED:
mPlayPauseButton.setImageDrawable(
mResources.getDrawable(R.drawable.ic_replay_circle_filled, null));
- mPlayPauseButton.setContentDescription(mReplayDescription);
+ mPlayPauseButton.setContentDescription(
+ mResources.getString(R.string.mcv2_replay_button_desc));
mIsStopped = true;
break;
default:
diff --git a/packages/MediaComponents/tests/Android.mk b/packages/MediaComponents/tests/Android.mk
index bf81efb..dddfd2a 100644
--- a/packages/MediaComponents/tests/Android.mk
+++ b/packages/MediaComponents/tests/Android.mk
@@ -20,6 +20,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android.test.runner.stubs \
android.test.base.stubs \
+ mockito-target-minus-junit4 \
junit
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java b/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
index 80370ec..55a34fd 100644
--- a/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
+++ b/packages/MediaComponents/tests/src/com/android/media/SessionPlaylistAgentTest.java
@@ -16,23 +16,27 @@
package com.android.media;
+import static org.mockito.Mockito.*;
+
import android.content.Context;
+import android.media.AudioAttributes;
import android.media.DataSourceDesc;
import android.media.MediaItem2;
import android.media.MediaMetadata2;
-import android.media.MediaPlayer2;
import android.media.MediaPlayerBase;
+import android.media.MediaPlayerBase.PlayerEventCallback;
import android.media.MediaPlaylistAgent;
import android.media.MediaSession2;
+import android.media.MediaSession2.OnDataSourceMissingHelper;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.test.AndroidTestCase;
-import android.util.Log;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Matchers;
import java.util.ArrayList;
import java.util.List;
@@ -52,10 +56,11 @@
private Object mWaitLock = new Object();
private Context mContext;
- private MediaSession2 mSession;
+ private MediaSession2Impl mSessionImpl;
private MediaPlayerBase mPlayer;
+ private PlayerEventCallback mPlayerEventCallback;
private SessionPlaylistAgent mAgent;
- private MyDataSourceHelper mDataSourceHelper;
+ private OnDataSourceMissingHelper mDataSourceHelper;
private MyPlaylistEventCallback mEventCallback;
public class MyPlaylistEventCallback extends MediaPlaylistAgent.PlaylistEventCallback {
@@ -108,7 +113,7 @@
}
}
- public class MyDataSourceHelper implements MediaSession2.OnDataSourceMissingHelper {
+ public class MyDataSourceHelper implements OnDataSourceMissingHelper {
@Override
public DataSourceDesc onDataSourceMissing(MediaSession2 session, MediaItem2 item) {
if (item.getMediaId().contains("WITHOUT_DSD")) {
@@ -121,8 +126,104 @@
}
}
+ public class MockPlayer extends MediaPlayerBase {
+ @Override
+ public void play() {
+ }
+
+ @Override
+ public void prepare() {
+ }
+
+ @Override
+ public void pause() {
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ @Override
+ public void skipToNext() {
+ }
+
+ @Override
+ public void seekTo(long pos) {
+ }
+
+ @Override
+ public int getPlayerState() {
+ return 0;
+ }
+
+ @Override
+ public int getBufferingState() {
+ return 0;
+ }
+
+ @Override
+ public void setAudioAttributes(AudioAttributes attributes) {
+ }
+
+ @Override
+ public AudioAttributes getAudioAttributes() {
+ return null;
+ }
+
+ @Override
+ public void setDataSource(DataSourceDesc dsd) {
+ }
+
+ @Override
+ public void setNextDataSource(DataSourceDesc dsd) {
+ }
+
+ @Override
+ public void setNextDataSources(List<DataSourceDesc> dsds) {
+ }
+
+ @Override
+ public DataSourceDesc getCurrentDataSource() {
+ return null;
+ }
+
+ @Override
+ public void loopCurrent(boolean loop) {
+ }
+
+ @Override
+ public void setPlaybackSpeed(float speed) {
+ }
+
+ @Override
+ public void setPlayerVolume(float volume) {
+ }
+
+ @Override
+ public float getPlayerVolume() {
+ return 0;
+ }
+
+ @Override
+ public void registerPlayerEventCallback(Executor e, PlayerEventCallback cb) {
+ }
+
+ @Override
+ public void unregisterPlayerEventCallback(PlayerEventCallback cb) {
+ }
+
+ @Override
+ public void close() throws Exception {
+ }
+ }
+
@Before
public void setUp() throws Exception {
+ mContext = getContext();
+ // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
+ // Dexmaker is used by mockito.
+ System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
+
HandlerThread handlerThread = new HandlerThread("SessionPlaylistAgent");
handlerThread.start();
mHandler = new Handler(handlerThread.getLooper());
@@ -130,15 +231,16 @@
mHandler.post(runnable);
};
- mContext = getContext();
- mPlayer = MediaPlayer2.create();
- mSession = new MediaSession2.Builder(mContext)
- .setPlayer(mPlayer)
- .setSessionCallback(mHandlerExecutor,
- new MediaSession2.SessionCallback(mContext) {})
- .setId(TAG).build();
+ mPlayer = mock(MockPlayer.class);
+ doAnswer(invocation -> {
+ Object[] args = invocation.getArguments();
+ mPlayerEventCallback = (PlayerEventCallback) args[1];
+ return null;
+ }).when(mPlayer).registerPlayerEventCallback(Matchers.any(), Matchers.any());
+
+ mSessionImpl = mock(MediaSession2Impl.class);
mDataSourceHelper = new MyDataSourceHelper();
- mAgent = new SessionPlaylistAgent(mContext, mSession, mPlayer);
+ mAgent = new SessionPlaylistAgent(mContext, mSessionImpl, mPlayer);
mAgent.setOnDataSourceMissingHelper(mDataSourceHelper);
mEventCallback = new MyPlaylistEventCallback(mWaitLock);
mAgent.registerPlaylistEventCallback(mHandlerExecutor, mEventCallback);
@@ -146,8 +248,6 @@
@After
public void tearDown() throws Exception {
- mSession.close();
- mPlayer.close();
mHandler.getLooper().quitSafely();
mHandler = null;
mHandlerExecutor = null;
@@ -476,6 +576,33 @@
assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
}
+ @Test
+ public void testPlaylistAfterOnCurrentDataSourceChanged() throws Exception {
+ int listSize = 2;
+ verify(mPlayer).registerPlayerEventCallback(Matchers.any(), Matchers.any());
+
+ createAndSetPlaylist(listSize);
+ assertEquals(0, mAgent.getCurShuffledIndex());
+
+ mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
+ assertEquals(1, mAgent.getCurShuffledIndex());
+ mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
+ assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
+
+ mAgent.skipToNextItem();
+ assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
+
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ONE);
+ assertEquals(SessionPlaylistAgent.END_OF_PLAYLIST, mAgent.getCurShuffledIndex());
+
+ mAgent.setRepeatMode(MediaPlaylistAgent.REPEAT_MODE_ALL);
+ assertEquals(0, mAgent.getCurShuffledIndex());
+ mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
+ assertEquals(1, mAgent.getCurShuffledIndex());
+ mPlayerEventCallback.onCurrentDataSourceChanged(mPlayer, null);
+ assertEquals(0, mAgent.getCurShuffledIndex());
+ }
+
private List<MediaItem2> createAndSetPlaylist(int listSize) throws Exception {
List<MediaItem2> items = new ArrayList<>();
for (int i = 0; i < listSize; ++i) {
diff --git a/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h b/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h
index 31b7e0f..e4fd176 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/audio_policy_criteria_conf.h
@@ -62,7 +62,8 @@
[AUDIO_POLICY_FORCE_FOR_DOCK] = "ForceUseForDock",
[AUDIO_POLICY_FORCE_FOR_SYSTEM] = "ForceUseForSystem",
[AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] = "ForceUseForHdmiSystemAudio",
- [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] = "ForceUseForEncodedSurround"
+ [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] = "ForceUseForEncodedSurround",
+ [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] = "ForceUseForVibrateRinging"
};
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 977a396..be7f7ec 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -154,6 +154,13 @@
}
mForceUse[usage] = config;
break;
+ case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
+ if (config != AUDIO_POLICY_FORCE_BT_SCO && config != AUDIO_POLICY_FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_VIBRATE_RINGING", config);
+ return BAD_VALUE;
+ }
+ mForceUse[usage] = config;
+ break;
default:
ALOGW("setForceUse() invalid usage %d", usage);
break; // TODO return BAD_VALUE?
@@ -423,8 +430,7 @@
// if SCO headset is connected and we are told to use it, play ringtone over
// speaker and BT SCO
- if (((availableOutputDevicesType & AUDIO_DEVICE_OUT_ALL_SCO) != 0) &&
- (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO)) {
+ if ((availableOutputDevicesType & AUDIO_DEVICE_OUT_ALL_SCO) != 0) {
uint32_t device2 = AUDIO_DEVICE_NONE;
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
if (device2 == AUDIO_DEVICE_NONE) {
@@ -433,10 +439,23 @@
if (device2 == AUDIO_DEVICE_NONE) {
device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
}
-
- if (device2 != AUDIO_DEVICE_NONE) {
- device |= device2;
- break;
+ // Use ONLY Bluetooth SCO output when ringing in vibration mode
+ if (!((mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
+ && (strategy == STRATEGY_ENFORCED_AUDIBLE))) {
+ if (mForceUse[AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING]
+ == AUDIO_POLICY_FORCE_BT_SCO) {
+ if (device2 != AUDIO_DEVICE_NONE) {
+ device = device2;
+ break;
+ }
+ }
+ }
+ // Use both Bluetooth SCO and phone default output when ringing in normal mode
+ if (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION] == AUDIO_POLICY_FORCE_BT_SCO) {
+ if (device2 != AUDIO_DEVICE_NONE) {
+ device |= device2;
+ break;
+ }
}
}
// The second device used for sonification is the same as the device used by media strategy
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 73d92ac..92a2030 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -5141,7 +5141,8 @@
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
AUDIO_DEVICE_OUT_WIRED_HEADSET |
AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
- AUDIO_DEVICE_OUT_USB_HEADSET)) &&
+ AUDIO_DEVICE_OUT_USB_HEADSET |
+ AUDIO_DEVICE_OUT_HEARING_AID)) &&
((stream_strategy == STRATEGY_SONIFICATION)
|| (stream_strategy == STRATEGY_SONIFICATION_RESPECTFUL)
|| (stream == AUDIO_STREAM_SYSTEM)
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index fb9b0ba..9ed6d73 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1999,14 +1999,17 @@
// A reference count is kept to determine when we will actually release the
// media players.
-MediaPlayer* CameraService::newMediaPlayer(const char *file) {
- MediaPlayer* mp = new MediaPlayer();
- if (mp->setDataSource(NULL /* httpService */, file, NULL) == NO_ERROR) {
+sp<MediaPlayer> CameraService::newMediaPlayer(const char *file) {
+ sp<MediaPlayer> mp = new MediaPlayer();
+ status_t error;
+ if ((error = mp->setDataSource(NULL /* httpService */, file, NULL)) == NO_ERROR) {
mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE);
- mp->prepare();
- } else {
+ error = mp->prepare();
+ }
+ if (error != NO_ERROR) {
ALOGE("Failed to load CameraService sounds: %s", file);
- delete mp;
+ mp->disconnect();
+ mp.clear();
return nullptr;
}
return mp;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 86a2b81..a7a9264 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -736,7 +736,7 @@
std::vector<std::string> mNormalDeviceIds;
// sounds
- MediaPlayer* newMediaPlayer(const char *file);
+ sp<MediaPlayer> newMediaPlayer(const char *file);
Mutex mSoundLock;
sp<MediaPlayer> mSoundPlayer[NUM_SOUNDS];
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 7b8d817..11fd9f6 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -201,14 +201,14 @@
if (endpoint.get() != nullptr) {
aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
- ALOGE("openSharedEndpoint(), open failed");
+ ALOGE("%s(), open failed", __func__);
endpoint.clear();
} else {
mSharedStreams.push_back(endpoint);
}
}
- ALOGD("openSharedEndpoint(), created %p, requested device = %d, dir = %d",
- endpoint.get(), configuration.getDeviceId(), (int)direction);
+ ALOGD("%s(), created endpoint %p, requested device = %d, dir = %d",
+ __func__, endpoint.get(), configuration.getDeviceId(), (int)direction);
IPCThreadState::self()->restoreCallingIdentity(token);
}
@@ -244,8 +244,8 @@
mExclusiveStreams.end());
serviceEndpoint->close();
- ALOGD("closeExclusiveEndpoint() %p for device %d",
- serviceEndpoint.get(), serviceEndpoint->getDeviceId());
+ ALOGD("%s() %p for device %d",
+ __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
@@ -266,7 +266,7 @@
mSharedStreams.end());
serviceEndpoint->close();
- ALOGD("closeSharedEndpoint() %p for device %d",
- serviceEndpoint.get(), serviceEndpoint->getDeviceId());
+ ALOGD("%s() %p for device %d",
+ __func__, serviceEndpoint.get(), serviceEndpoint->getDeviceId());
}
}
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index c708fee..ad5bb3a 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -165,7 +165,6 @@
}
aaudio_result_t AAudioService::closeStream(aaudio_handle_t streamHandle) {
- ALOGD("closeStream(0x%08X)", streamHandle);
// Check permission and ownership first.
sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index 33439fc..96e621a 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -39,7 +39,7 @@
using namespace aaudio; // TODO just import names needed
AAudioServiceEndpoint::~AAudioServiceEndpoint() {
- ALOGD("AAudioServiceEndpoint::~AAudioServiceEndpoint() destroying endpoint %p", this);
+ ALOGD("%s(%p) destroyed", __func__, this);
}
std::string AAudioServiceEndpoint::dump() const {
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index db01c88..52990da 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -98,8 +98,8 @@
.flags = AUDIO_FLAG_LOW_LATENCY,
.tags = ""
};
- ALOGV("open() MMAP attributes.usage = %d, content_type = %d, source = %d",
- attributes.usage, attributes.content_type, attributes.source);
+ ALOGD("%s(%p) MMAP attributes.usage = %d, content_type = %d, source = %d",
+ __func__, this, attributes.usage, attributes.content_type, attributes.source);
mMmapClient.clientUid = request.getUserId();
mMmapClient.clientPid = request.getProcessId();
@@ -135,7 +135,7 @@
mHardwareTimeOffsetNanos = INPUT_ESTIMATED_HARDWARE_OFFSET_NANOS; // frames at ADC earlier
} else {
- ALOGE("openMmapStream - invalid direction = %d", direction);
+ ALOGE("%s() invalid direction = %d", __func__, direction);
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
@@ -157,20 +157,20 @@
this, // callback
mMmapStream,
&mPortHandle);
- ALOGD("open() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
- mMmapClient.clientUid, mMmapClient.clientPid, mPortHandle);
+ ALOGD("%s() mMapClient.uid = %d, pid = %d => portHandle = %d\n",
+ __func__, mMmapClient.clientUid, mMmapClient.clientPid, mPortHandle);
if (status != OK) {
- ALOGE("openMmapStream returned status %d", status);
+ ALOGE("%s() openMmapStream() returned status %d", __func__, status);
return AAUDIO_ERROR_UNAVAILABLE;
}
if (deviceId == AAUDIO_UNSPECIFIED) {
- ALOGW("open() - openMmapStream() failed to set deviceId");
+ ALOGW("%s() openMmapStream() failed to set deviceId", __func__);
}
setDeviceId(deviceId);
if (sessionId == AUDIO_SESSION_ALLOCATE) {
- ALOGW("open() - openMmapStream() failed to set sessionId");
+ ALOGW("%s() - openMmapStream() failed to set sessionId", __func__);
}
aaudio_session_id_t actualSessionId =
@@ -178,7 +178,7 @@
? AAUDIO_SESSION_ID_NONE
: (aaudio_session_id_t) sessionId;
setSessionId(actualSessionId);
- ALOGD("open() deviceId = %d, sessionId = %d", getDeviceId(), getSessionId());
+ ALOGD("%s() deviceId = %d, sessionId = %d", __func__, getDeviceId(), getSessionId());
// Create MMAP/NOIRQ buffer.
int32_t minSizeFrames = getBufferCapacity();
@@ -187,14 +187,14 @@
}
status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
if (status != OK) {
- ALOGE("open() - createMmapBuffer() failed with status %d %s",
- status, strerror(-status));
+ ALOGE("%s() - createMmapBuffer() failed with status %d %s",
+ __func__, status, strerror(-status));
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
} else {
- ALOGD("createMmapBuffer status = %d, buffer_size = %d, burst_size %d"
+ ALOGD("%s() createMmapBuffer() returned = %d, buffer_size = %d, burst_size %d"
", Sharable FD: %s",
- status,
+ __func__, status,
abs(mMmapBufferinfo.buffer_size_frames),
mMmapBufferinfo.burst_size_frames,
mMmapBufferinfo.buffer_size_frames < 0 ? "Yes" : "No");
@@ -214,7 +214,7 @@
// Fallback is handled by caller but indicate what is possible in case
// this is used in the future
setSharingMode(AAUDIO_SHARING_MODE_SHARED);
- ALOGW("open() - exclusive FD cannot be used by client");
+ ALOGW("%s() - exclusive FD cannot be used by client", __func__);
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
}
@@ -229,7 +229,7 @@
// Assume that AudioFlinger will close the original shared_memory_fd.
mAudioDataFileDescriptor.reset(dup(mMmapBufferinfo.shared_memory_fd));
if (mAudioDataFileDescriptor.get() == -1) {
- ALOGE("open() - could not dup shared_memory_fd");
+ ALOGE("%s() - could not dup shared_memory_fd", __func__);
result = AAUDIO_ERROR_INTERNAL;
goto error;
}
@@ -247,12 +247,12 @@
burstMicros = mFramesPerBurst * static_cast<int64_t>(1000000) / getSampleRate();
} while (burstMicros < burstMinMicros);
- ALOGD("open() original burst = %d, minMicros = %d, to burst = %d\n",
- mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
+ ALOGD("%s() original burst = %d, minMicros = %d, to burst = %d\n",
+ __func__, mMmapBufferinfo.burst_size_frames, burstMinMicros, mFramesPerBurst);
- ALOGD("open() actual rate = %d, channels = %d"
+ ALOGD("%s() actual rate = %d, channels = %d"
", deviceId = %d, capacity = %d\n",
- getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
+ __func__, getSampleRate(), getSamplesPerFrame(), deviceId, getBufferCapacity());
return result;
@@ -262,9 +262,8 @@
}
aaudio_result_t AAudioServiceEndpointMMAP::close() {
-
if (mMmapStream != 0) {
- ALOGD("close() clear() endpoint");
+ ALOGD("%s() clear() endpoint", __func__);
// Needs to be explicitly cleared or CTS will fail but it is not clear why.
mMmapStream.clear();
// Apparently the above close is asynchronous. An attempt to open a new device
@@ -299,20 +298,18 @@
aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
audio_port_handle_t *clientHandle) {
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- ALOGD("startClient(%p(uid=%d, pid=%d))",
- &client, client.clientUid, client.clientPid);
+ ALOGV("%s(%p(uid=%d, pid=%d))", __func__, &client, client.clientUid, client.clientPid);
audio_port_handle_t originalHandle = *clientHandle;
status_t status = mMmapStream->start(client, clientHandle);
aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
- ALOGD("startClient() , %d => %d returns %d",
- originalHandle, *clientHandle, result);
+ ALOGV("%s() , %d => %d returns %d", __func__, originalHandle, *clientHandle, result);
return result;
}
aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
- ALOGD("stopClient(%d) returns %d", clientHandle, result);
+ ALOGV("%s(%d) returns %d", __func__, clientHandle, result);
return result;
}
@@ -324,13 +321,13 @@
return AAUDIO_ERROR_NULL;
}
status_t status = mMmapStream->getMmapPosition(&position);
- ALOGV("getFreeRunningPosition() status= %d, pos = %d, nanos = %lld\n",
- status, position.position_frames, (long long) position.time_nanoseconds);
+ ALOGV("%s() status= %d, pos = %d, nanos = %lld\n",
+ __func__, status, position.position_frames, (long long) position.time_nanoseconds);
aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
if (result == AAUDIO_ERROR_UNAVAILABLE) {
- ALOGW("sendCurrentTimestamp(): getMmapPosition() has no position data available");
+ ALOGW("%s(): getMmapPosition() has no position data available", __func__);
} else if (result != AAUDIO_OK) {
- ALOGE("sendCurrentTimestamp(): getMmapPosition() returned status %d", status);
+ ALOGE("%s(): getMmapPosition() returned status %d", __func__, status);
} else {
// Convert 32-bit position to 64-bit position.
mFramesTransferred.update32(position.position_frames);
@@ -347,15 +344,16 @@
void AAudioServiceEndpointMMAP::onTearDown() {
- ALOGD("onTearDown() called");
+ ALOGD("%s(%p) called", __func__, this);
disconnectRegisteredStreams();
};
void AAudioServiceEndpointMMAP::onVolumeChanged(audio_channel_mask_t channels,
android::Vector<float> values) {
- // TODO do we really need a different volume for each channel?
+ // TODO Do we really need a different volume for each channel?
+ // We get called with an array filled with a single value!
float volume = values[0];
- ALOGD("onVolumeChanged() volume[0] = %f", volume);
+ ALOGD("%s(%p) volume[0] = %f", __func__, this, volume);
std::lock_guard<std::mutex> lock(mLockStreams);
for(const auto stream : mRegisteredStreams) {
stream->onVolumeChanged(volume);
@@ -363,8 +361,7 @@
};
void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t deviceId) {
- ALOGD("onRoutingChanged() called with dev %d, old = %d",
- deviceId, getDeviceId());
+ ALOGD("%s(%p) called with dev %d, old = %d", __func__, this, deviceId, getDeviceId());
if (getDeviceId() != AUDIO_PORT_HANDLE_NONE && getDeviceId() != deviceId) {
disconnectRegisteredStreams();
}
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 2601f3f..a274466 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -43,10 +43,12 @@
AAudioServiceEndpointPlay::AAudioServiceEndpointPlay(AAudioService &audioService)
: mStreamInternalPlay(audioService, true) {
+ ALOGD("%s(%p) created", __func__, this);
mStreamInternal = &mStreamInternalPlay;
}
AAudioServiceEndpointPlay::~AAudioServiceEndpointPlay() {
+ ALOGD("%s(%p) destroyed", __func__, this);
}
aaudio_result_t AAudioServiceEndpointPlay::open(const aaudio::AAudioStreamRequest &request) {
@@ -68,6 +70,7 @@
// Mix data from each application stream and write result to the shared MMAP stream.
void *AAudioServiceEndpointPlay::callbackLoop() {
+ ALOGD("%s() entering >>>>>>>>>>>>>>> MIXER", __func__);
aaudio_result_t result = AAUDIO_OK;
int64_t timeoutNanos = getStreamInternal()->calculateReasonableTimeout();
@@ -152,5 +155,7 @@
}
}
+ ALOGD("%s() exiting, enabled = %d, state = %d, result = %d <<<<<<<<<<<<< MIXER",
+ __func__, mCallbackEnabled.load(), getStreamInternal()->getState(), result);
return NULL; // TODO review
}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 584efe5..f08a52f 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -89,18 +89,22 @@
}
// Glue between C and C++ callbacks.
-static void *aaudio_endpoint_thread_proc(void *context) {
- AAudioServiceEndpointShared *endpoint = (AAudioServiceEndpointShared *) context;
- if (endpoint != NULL) {
- void *result = endpoint->callbackLoop();
- // Close now so that the HW resource is freed and we can open a new device.
- if (!endpoint->isConnected()) {
- endpoint->close();
- }
- return result;
- } else {
- return NULL;
+static void *aaudio_endpoint_thread_proc(void *arg) {
+ assert(arg != nullptr);
+
+ // The caller passed in a smart pointer to prevent the endpoint from getting deleted
+ // while the thread was launching.
+ sp<AAudioServiceEndpointShared> *endpointForThread =
+ static_cast<sp<AAudioServiceEndpointShared> *>(arg);
+ sp<AAudioServiceEndpointShared> endpoint = *endpointForThread;
+ delete endpointForThread; // Just use scoped smart pointer. Don't need this anymore.
+ void *result = endpoint->callbackLoop();
+ // Close now so that the HW resource is freed and we can open a new device.
+ if (!endpoint->isConnected()) {
+ endpoint->close();
}
+
+ return result;
}
aaudio_result_t aaudio::AAudioServiceEndpointShared::startSharingThread_l() {
@@ -109,7 +113,16 @@
* AAUDIO_NANOS_PER_SECOND
/ getSampleRate();
mCallbackEnabled.store(true);
- return getStreamInternal()->createThread(periodNanos, aaudio_endpoint_thread_proc, this);
+ // Pass a smart pointer so the thread can hold a reference.
+ sp<AAudioServiceEndpointShared> *endpointForThread = new sp<AAudioServiceEndpointShared>(this);
+ aaudio_result_t result = getStreamInternal()->createThread(periodNanos,
+ aaudio_endpoint_thread_proc,
+ endpointForThread);
+ if (result != AAUDIO_OK) {
+ // The thread can't delete it so we have to do it here.
+ delete endpointForThread;
+ }
+ return result;
}
aaudio_result_t aaudio::AAudioServiceEndpointShared::stopSharingThread() {
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 74cd817..227250c 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -54,12 +54,13 @@
virtual void *callbackLoop() = 0;
+
+protected:
+
AudioStreamInternal *getStreamInternal() const {
return mStreamInternal;
};
-protected:
-
aaudio_result_t startSharingThread_l();
aaudio_result_t stopSharingThread();
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index e8c9e41..18f14ee 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -93,7 +93,7 @@
{
std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
if (mUpMessageQueue != nullptr) {
- ALOGE("open() called twice");
+ ALOGE("%s() called twice", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -108,7 +108,7 @@
request,
sharingMode);
if (mServiceEndpoint == nullptr) {
- ALOGE("open() openEndpoint() failed");
+ ALOGE("%s() openEndpoint() failed", __func__);
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
}
@@ -167,7 +167,7 @@
}
if (mServiceEndpoint == nullptr) {
- ALOGE("start() missing endpoint");
+ ALOGE("%s() missing endpoint", __func__);
result = AAUDIO_ERROR_INVALID_STATE;
goto error;
}
@@ -201,7 +201,7 @@
return result;
}
if (mServiceEndpoint == nullptr) {
- ALOGE("pause() missing endpoint");
+ ALOGE("%s() missing endpoint", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -217,7 +217,7 @@
result = mServiceEndpoint->stopStream(this, mClientHandle);
if (result != AAUDIO_OK) {
- ALOGE("pause() mServiceEndpoint returned %d", result);
+ ALOGE("%s() mServiceEndpoint returned %d, %s", __func__, result, getTypeText());
disconnect(); // TODO should we return or pause Base first?
}
@@ -233,7 +233,7 @@
}
if (mServiceEndpoint == nullptr) {
- ALOGE("stop() missing endpoint");
+ ALOGE("%s() missing endpoint", __func__);
return AAUDIO_ERROR_INVALID_STATE;
}
@@ -251,7 +251,7 @@
// TODO wait for data to be played out
result = mServiceEndpoint->stopStream(this, mClientHandle);
if (result != AAUDIO_OK) {
- ALOGE("stop() mServiceEndpoint returned %d", result);
+ ALOGE("%s() mServiceEndpoint returned %d, %s", __func__, result, getTypeText());
disconnect();
// TODO what to do with result here?
}
@@ -284,7 +284,7 @@
// implement Runnable, periodically send timestamps to client
void AAudioServiceStreamBase::run() {
- ALOGD("run() entering ----------------");
+ ALOGD("%s() %s entering >>>>>>>>>>>>>> TIMESTAMPS", __func__, getTypeText());
TimestampScheduler timestampScheduler;
timestampScheduler.setBurstPeriod(mFramesPerBurst, getSampleRate());
timestampScheduler.start(AudioClock::getNanoseconds());
@@ -302,7 +302,7 @@
AudioClock::sleepUntilNanoTime(nextTime);
}
}
- ALOGD("run() exiting ----------------");
+ ALOGD("%s() %s exiting <<<<<<<<<<<<<< TIMESTAMPS", __func__, getTypeText());
}
void AAudioServiceStreamBase::disconnect() {
@@ -333,12 +333,12 @@
aaudio_result_t AAudioServiceStreamBase::writeUpMessageQueue(AAudioServiceMessage *command) {
std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
if (mUpMessageQueue == nullptr) {
- ALOGE("writeUpMessageQueue(): mUpMessageQueue null! - stream not open");
+ ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
return AAUDIO_ERROR_NULL;
}
int32_t count = mUpMessageQueue->getFifoBuffer()->write(command, 1);
if (count != 1) {
- ALOGE("writeUpMessageQueue(): Queue full. Did client die?");
+ ALOGE("%s(): Queue full. Did client die? %s", __func__, getTypeText());
return AAUDIO_ERROR_WOULD_BLOCK;
} else {
return AAUDIO_OK;
@@ -355,7 +355,7 @@
aaudio_result_t result = getFreeRunningPosition(&command.timestamp.position,
&command.timestamp.timestamp);
if (result == AAUDIO_OK) {
- ALOGV("sendCurrentTimestamp() SERVICE %8lld at %lld",
+ ALOGV("%s() SERVICE %8lld at %lld", __func__,
(long long) command.timestamp.position,
(long long) command.timestamp.timestamp);
command.what = AAudioServiceMessage::code::TIMESTAMP_SERVICE;
@@ -366,7 +366,7 @@
result = getHardwareTimestamp(&command.timestamp.position,
&command.timestamp.timestamp);
if (result == AAUDIO_OK) {
- ALOGV("sendCurrentTimestamp() HARDWARE %8lld at %lld",
+ ALOGV("%s() HARDWARE %8lld at %lld", __func__,
(long long) command.timestamp.position,
(long long) command.timestamp.timestamp);
command.what = AAudioServiceMessage::code::TIMESTAMP_HARDWARE;
@@ -389,7 +389,7 @@
{
std::lock_guard<std::mutex> lock(mUpMessageQueueLock);
if (mUpMessageQueue == nullptr) {
- ALOGE("getDescription(): mUpMessageQueue null! - stream not open");
+ ALOGE("%s(): mUpMessageQueue null! - stream not open", __func__);
return AAUDIO_ERROR_NULL;
}
// Gather information on the message queue.
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index 5f5bb98..3720596 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -55,7 +55,7 @@
, public Runnable {
public:
- AAudioServiceStreamBase(android::AAudioService &aAudioService);
+ explicit AAudioServiceStreamBase(android::AAudioService &aAudioService);
virtual ~AAudioServiceStreamBase();
@@ -219,6 +219,8 @@
mCloseNeeded.store(needed);
}
+ virtual const char *getTypeText() const { return "Base"; }
+
protected:
/**
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index e2415d0..1509f7d 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -69,9 +69,7 @@
aaudio_result_t close() override;
- /**
- * Send a MMAP/NOIRQ buffer timestamp to the client.
- */
+ const char *getTypeText() const override { return "MMAP"; }
protected:
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 3b12e61..61769b5 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -43,7 +43,7 @@
class AAudioServiceStreamShared : public AAudioServiceStreamBase {
public:
- AAudioServiceStreamShared(android::AAudioService &aAudioService);
+ explicit AAudioServiceStreamShared(android::AAudioService &aAudioService);
virtual ~AAudioServiceStreamShared() = default;
static std::string dumpHeader();
@@ -87,6 +87,8 @@
return mXRunCount.load();
}
+ const char *getTypeText() const override { return "Shared"; }
+
protected:
aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
diff --git a/services/oboeservice/AAudioThread.h b/services/oboeservice/AAudioThread.h
index ffc9b7b..dcce68a 100644
--- a/services/oboeservice/AAudioThread.h
+++ b/services/oboeservice/AAudioThread.h
@@ -44,7 +44,7 @@
public:
AAudioThread();
- AAudioThread(const char *prefix);
+ explicit AAudioThread(const char *prefix);
virtual ~AAudioThread() = default;