Merge "Wait for iref box if the heic file has Exif data"
diff --git a/cmds/screenrecord/Android.bp b/cmds/screenrecord/Android.bp
new file mode 100644
index 0000000..86476cd
--- /dev/null
+++ b/cmds/screenrecord/Android.bp
@@ -0,0 +1,55 @@
+// Copyright 2013 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.
+
+cc_binary {
+ name: "screenrecord",
+
+ srcs: [
+ "screenrecord.cpp",
+ "EglWindow.cpp",
+ "FrameOutput.cpp",
+ "TextRenderer.cpp",
+ "Overlay.cpp",
+ "Program.cpp",
+ ],
+
+ shared_libs: [
+ "libstagefright",
+ "libmedia",
+ "libmedia_omx",
+ "libutils",
+ "libbinder",
+ "libstagefright_foundation",
+ "libjpeg",
+ "libui",
+ "libgui",
+ "libcutils",
+ "liblog",
+ "libEGL",
+ "libGLESv2",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright",
+ "frameworks/av/media/libstagefright/include",
+ "frameworks/native/include/media/openmax",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wno-multichar",
+ //"-UNDEBUG",
+ ]
+}
diff --git a/cmds/screenrecord/Android.mk b/cmds/screenrecord/Android.mk
deleted file mode 100644
index 5e83ed6..0000000
--- a/cmds/screenrecord/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- screenrecord.cpp \
- EglWindow.cpp \
- FrameOutput.cpp \
- TextRenderer.cpp \
- Overlay.cpp \
- Program.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libmedia_omx libutils libbinder libstagefright_foundation \
- libjpeg libui libgui libcutils liblog libEGL libGLESv2
-
-LOCAL_C_INCLUDES := \
- frameworks/av/media/libstagefright \
- frameworks/av/media/libstagefright/include \
- frameworks/native/include/media/openmax \
- external/jpeg
-
-LOCAL_CFLAGS := -Werror -Wall
-LOCAL_CFLAGS += -Wno-multichar
-#LOCAL_CFLAGS += -UNDEBUG
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE:= screenrecord
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 34a9a40..bf36be0 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -46,6 +46,7 @@
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -628,7 +629,7 @@
fprintf(stderr, " -l(ist) components\n");
fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n");
fprintf(stderr, " -b bug to reproduce\n");
- fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n");
+ fprintf(stderr, " -i(nfo) dump codec info (profiles and color formats supported, details)\n");
fprintf(stderr, " -t(humbnail) extract video thumbnail or album art\n");
fprintf(stderr, " -s(oftware) prefer software codec\n");
fprintf(stderr, " -r(hardware) force to use hardware codec\n");
@@ -646,55 +647,131 @@
fprintf(stderr, " -v be more verbose\n");
}
-static void dumpCodecProfiles(bool queryDecoders) {
- const char *kMimeTypes[] = {
- MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
- MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC,
- MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB,
- MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
- MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
- MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
- MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, MEDIA_MIMETYPE_VIDEO_HEVC,
- MEDIA_MIMETYPE_AUDIO_EAC3, MEDIA_MIMETYPE_AUDIO_AC4,
- MEDIA_MIMETYPE_VIDEO_AV1
- };
-
- const char *codecType = queryDecoders? "decoder" : "encoder";
- printf("%s profiles:\n", codecType);
+static void dumpCodecDetails(bool queryDecoders) {
+ const char *codecType = queryDecoders? "Decoder" : "Encoder";
+ printf("\n%s infos by media types:\n"
+ "=============================\n", codecType);
sp<IMediaCodecList> list = MediaCodecList::getInstance();
size_t numCodecs = list->countCodecs();
- for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++k) {
- printf("type '%s':\n", kMimeTypes[k]);
+ // gather all media types supported by codec class, and link to codecs that support them
+ KeyedVector<AString, Vector<sp<MediaCodecInfo>>> allMediaTypes;
+ for (size_t codec_ix = 0; codec_ix < numCodecs; ++codec_ix) {
+ sp<MediaCodecInfo> info = list->getCodecInfo(codec_ix);
+ if (info->isEncoder() == !queryDecoders) {
+ Vector<AString> supportedMediaTypes;
+ info->getSupportedMediaTypes(&supportedMediaTypes);
+ if (!supportedMediaTypes.size()) {
+ printf("warning: %s does not support any media types\n",
+ info->getCodecName());
+ } else {
+ for (const AString &mediaType : supportedMediaTypes) {
+ if (allMediaTypes.indexOfKey(mediaType) < 0) {
+ allMediaTypes.add(mediaType, Vector<sp<MediaCodecInfo>>());
+ }
+ allMediaTypes.editValueFor(mediaType).add(info);
+ }
+ }
+ }
+ }
- for (size_t index = 0; index < numCodecs; ++index) {
- sp<MediaCodecInfo> info = list->getCodecInfo(index);
- if (info == NULL || info->isEncoder() != !queryDecoders) {
- continue;
- }
- sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(kMimeTypes[k]);
+ KeyedVector<AString, bool> visitedCodecs;
+ for (size_t type_ix = 0; type_ix < allMediaTypes.size(); ++type_ix) {
+ const AString &mediaType = allMediaTypes.keyAt(type_ix);
+ printf("\nMedia type '%s':\n", mediaType.c_str());
+
+ for (const sp<MediaCodecInfo> &info : allMediaTypes.valueAt(type_ix)) {
+ sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(mediaType.c_str());
if (caps == NULL) {
+ printf("warning: %s does not have capabilities for type %s\n",
+ info->getCodecName(), mediaType.c_str());
continue;
}
- printf(" %s '%s' supports ",
+ printf(" %s \"%s\" supports\n",
codecType, info->getCodecName());
- Vector<MediaCodecInfo::ProfileLevel> profileLevels;
- caps->getSupportedProfileLevels(&profileLevels);
- if (profileLevels.size() == 0) {
- printf("NOTHING.\n");
- continue;
+ auto printList = [](const char *type, const Vector<AString> &values){
+ printf(" %s: [", type);
+ for (size_t j = 0; j < values.size(); ++j) {
+ printf("\n %s%s", values[j].c_str(),
+ j == values.size() - 1 ? " " : ",");
+ }
+ printf("]\n");
+ };
+
+ if (visitedCodecs.indexOfKey(info->getCodecName()) < 0) {
+ visitedCodecs.add(info->getCodecName(), true);
+ {
+ Vector<AString> aliases;
+ info->getAliases(&aliases);
+ // quote alias
+ for (AString &alias : aliases) {
+ alias.insert("\"", 1, 0);
+ alias.append('"');
+ }
+ printList("aliases", aliases);
+ }
+ {
+ uint32_t attrs = info->getAttributes();
+ Vector<AString> list;
+ list.add(AStringPrintf("encoder: %d", !!(attrs & MediaCodecInfo::kFlagIsEncoder)));
+ list.add(AStringPrintf("vendor: %d", !!(attrs & MediaCodecInfo::kFlagIsVendor)));
+ list.add(AStringPrintf("software-only: %d", !!(attrs & MediaCodecInfo::kFlagIsSoftwareOnly)));
+ list.add(AStringPrintf("hw-accelerated: %d", !!(attrs & MediaCodecInfo::kFlagIsHardwareAccelerated)));
+ printList(AStringPrintf("attributes: %#x", attrs).c_str(), list);
+ }
+
+ printf(" owner: \"%s\"\n", info->getOwnerName());
+ printf(" rank: %u\n", info->getRank());
+ } else {
+ printf(" aliases, attributes, owner, rank: see above\n");
}
- for (size_t j = 0; j < profileLevels.size(); ++j) {
- const MediaCodecInfo::ProfileLevel &profileLevel = profileLevels[j];
+ {
+ Vector<AString> list;
+ Vector<MediaCodecInfo::ProfileLevel> profileLevels;
+ caps->getSupportedProfileLevels(&profileLevels);
+ for (const MediaCodecInfo::ProfileLevel &pl : profileLevels) {
+ const char *niceProfile =
+ mediaType.equalsIgnoreCase(MIMETYPE_AUDIO_AAC) ? asString_AACObject(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2) ? asString_MPEG2Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263) ? asString_H263Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4) ? asString_MPEG4Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC) ? asString_AVCProfile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8) ? asString_VP8Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC) ? asString_HEVCProfile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9) ? asString_VP9Profile(pl.mProfile) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1) ? asString_AV1Profile(pl.mProfile) :"??";
+ const char *niceLevel =
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG2) ? asString_MPEG2Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_H263) ? asString_H263Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_MPEG4) ? asString_MPEG4Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AVC) ? asString_AVCLevel(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP8) ? asString_VP8Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_HEVC) ? asString_HEVCTierLevel(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_VP9) ? asString_VP9Level(pl.mLevel) :
+ mediaType.equalsIgnoreCase(MIMETYPE_VIDEO_AV1) ? asString_AV1Level(pl.mLevel) :
+ "??";
- printf("%s%u/%u", j > 0 ? ", " : "",
- profileLevel.mProfile, profileLevel.mLevel);
+ list.add(AStringPrintf("% 5u/% 5u (%s/%s)",
+ pl.mProfile, pl.mLevel, niceProfile, niceLevel));
+ }
+ printList("profile/levels", list);
}
- printf("\n");
+ {
+ Vector<AString> list;
+ Vector<uint32_t> colors;
+ caps->getSupportedColorFormats(&colors);
+ for (uint32_t color : colors) {
+ list.add(AStringPrintf("%#x (%s)", color,
+ asString_ColorFormat((int32_t)color)));
+ }
+ printList("colors", list);
+ }
+
+ printf(" details: %s\n", caps->getDetails()->debugString(6).c_str());
}
}
}
@@ -704,7 +781,7 @@
bool audioOnly = false;
bool listComponents = false;
- bool dumpProfiles = false;
+ bool dumpCodecInfo = false;
bool extractThumbnail = false;
bool seekTest = false;
bool useSurfaceAlloc = false;
@@ -724,7 +801,7 @@
sp<android::ALooper> looper;
int res;
- while ((res = getopt(argc, argv, "vhaqn:lm:b:ptsrow:kN:xSTd:D:")) >= 0) {
+ while ((res = getopt(argc, argv, "vhaqn:lm:b:itsrow:kN:xSTd:D:")) >= 0) {
switch (res) {
case 'a':
{
@@ -794,9 +871,9 @@
break;
}
- case 'p':
+ case 'i':
{
- dumpProfiles = true;
+ dumpCodecInfo = true;
break;
}
@@ -937,9 +1014,9 @@
return 0;
}
- if (dumpProfiles) {
- dumpCodecProfiles(true /* queryDecoders */);
- dumpCodecProfiles(false /* queryDecoders */);
+ if (dumpCodecInfo) {
+ dumpCodecDetails(true /* queryDecoders */);
+ dumpCodecDetails(false /* queryDecoders */);
}
if (listComponents) {
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 480c7cd..5888af0 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -168,7 +168,7 @@
case OfflineLicenseState::USABLE:
return DrmPlugin::kOfflineLicenseStateUsable;
case OfflineLicenseState::INACTIVE:
- return DrmPlugin::kOfflineLicenseStateInactive;
+ return DrmPlugin::kOfflineLicenseStateReleased;
default:
return DrmPlugin::kOfflineLicenseStateUnknown;
}
@@ -586,51 +586,57 @@
return Void();
}
-bool DrmHal::matchMimeTypeAndSecurityLevel(sp<IDrmFactory> &factory,
- const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level) {
- if (mimeType == "") {
- return true;
- } else if (!factory->isContentTypeSupported(mimeType.string())) {
- return false;
+status_t DrmHal::matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
+ const uint8_t uuid[16],
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported) {
+ *isSupported = false;
+
+ // handle default value cases
+ if (level == DrmPlugin::kSecurityLevelUnknown) {
+ if (mimeType == "") {
+ // isCryptoSchemeSupported(uuid)
+ *isSupported = true;
+ } else {
+ // isCryptoSchemeSupported(uuid, mimeType)
+ *isSupported = factory->isContentTypeSupported(mimeType.string());
+ }
+ return OK;
+ } else if (mimeType == "") {
+ return BAD_VALUE;
}
- if (level == DrmPlugin::kSecurityLevelUnknown) {
- return true;
+ sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
+ if (factoryV1_2 == NULL) {
+ return ERROR_UNSUPPORTED;
} else {
- sp<drm::V1_2::IDrmFactory> factoryV1_2 = drm::V1_2::IDrmFactory::castFrom(factory);
- if (factoryV1_2 == NULL) {
- return true;
- } else if (factoryV1_2->isCryptoSchemeSupported_1_2(uuid,
- mimeType.string(), toHidlSecurityLevel(level))) {
- return true;
- }
+ *isSupported = factoryV1_2->isCryptoSchemeSupported_1_2(uuid,
+ mimeType.string(), toHidlSecurityLevel(level));
+ return OK;
}
- return false;
}
-bool DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level) {
+status_t DrmHal::isCryptoSchemeSupported(const uint8_t uuid[16],
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported) {
Mutex::Autolock autoLock(mLock);
-
- for (size_t i = 0; i < mFactories.size(); i++) {
- sp<IDrmFactory> factory = mFactories[i];
- if (factory->isCryptoSchemeSupported(uuid)) {
- if (matchMimeTypeAndSecurityLevel(factory, uuid, mimeType, level)) {
- return true;
- }
+ *isSupported = false;
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
+ if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+ return matchMimeTypeAndSecurityLevel(mFactories[i],
+ uuid, mimeType, level, isSupported);
}
}
- return false;
+ return OK;
}
status_t DrmHal::createPlugin(const uint8_t uuid[16],
const String8& appPackageName) {
Mutex::Autolock autoLock(mLock);
- for (size_t i = mFactories.size() - 1; i >= 0; i--) {
+ for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
auto plugin = makeDrmPlugin(mFactories[i], uuid, appPackageName);
if (plugin != NULL) {
@@ -1213,7 +1219,7 @@
}
if (mPluginV1_2 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
+ return ERROR_UNSUPPORTED;
}
status_t err = UNKNOWN_ERROR;
@@ -1238,7 +1244,7 @@
}
if (mPluginV1_2 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
+ return ERROR_UNSUPPORTED;
}
Return<Status> status = mPluginV1_2->removeOfflineLicense(toHidlVec(keySetId));
@@ -1254,7 +1260,7 @@
}
if (mPluginV1_2 == NULL) {
- return ERROR_DRM_CANNOT_HANDLE;
+ return ERROR_UNSUPPORTED;
}
*licenseState = DrmPlugin::kOfflineLicenseStateUnknown;
@@ -1550,22 +1556,22 @@
void DrmHal::reportFrameworkMetrics() const
{
- MediaAnalyticsItem item("mediadrm");
- item.generateSessionID();
- item.setPkgName(mMetrics.GetAppPackageName().c_str());
+ std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("mediadrm"));
+ item->generateSessionID();
+ item->setPkgName(mMetrics.GetAppPackageName().c_str());
String8 vendor;
String8 description;
status_t result = getPropertyStringInternal(String8("vendor"), vendor);
if (result != OK) {
ALOGE("Failed to get vendor from drm plugin: %d", result);
} else {
- item.setCString("vendor", vendor.c_str());
+ item->setCString("vendor", vendor.c_str());
}
result = getPropertyStringInternal(String8("description"), description);
if (result != OK) {
ALOGE("Failed to get description from drm plugin: %d", result);
} else {
- item.setCString("description", description.c_str());
+ item->setCString("description", description.c_str());
}
std::string serializedMetrics;
@@ -1576,9 +1582,9 @@
std::string b64EncodedMetrics = toBase64StringNoPad(serializedMetrics.data(),
serializedMetrics.size());
if (!b64EncodedMetrics.empty()) {
- item.setCString("serialized_metrics", b64EncodedMetrics.c_str());
+ item->setCString("serialized_metrics", b64EncodedMetrics.c_str());
}
- if (!item.selfrecord()) {
+ if (!item->selfrecord()) {
ALOGE("Failed to self record framework metrics");
}
}
diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp
index 0f34315..51274d1 100644
--- a/drm/libmediadrm/IDrm.cpp
+++ b/drm/libmediadrm/IDrm.cpp
@@ -83,8 +83,8 @@
return reply.readInt32();
}
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
- DrmPlugin::SecurityLevel level) {
+ virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16], const String8 &mimeType,
+ DrmPlugin::SecurityLevel level, bool *isSupported) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
data.write(uuid, 16);
@@ -94,10 +94,11 @@
status_t status = remote()->transact(IS_CRYPTO_SUPPORTED, data, &reply);
if (status != OK) {
ALOGE("isCryptoSchemeSupported: binder call failed: %d", status);
- return false;
+ return status;
}
+ *isSupported = static_cast<bool>(reply.readInt32());
- return reply.readInt32() != 0;
+ return reply.readInt32();
}
virtual status_t createPlugin(const uint8_t uuid[16],
@@ -773,7 +774,10 @@
String8 mimeType = data.readString8();
DrmPlugin::SecurityLevel level =
static_cast<DrmPlugin::SecurityLevel>(data.readInt32());
- reply->writeInt32(isCryptoSchemeSupported(uuid, mimeType, level));
+ bool isSupported = false;
+ status_t result = isCryptoSchemeSupported(uuid, mimeType, level, &isSupported);
+ reply->writeInt32(isSupported);
+ reply->writeInt32(result);
return OK;
}
diff --git a/drm/libmediadrm/PluginMetricsReporting.cpp b/drm/libmediadrm/PluginMetricsReporting.cpp
index 5cb48bf..8cd6f96 100644
--- a/drm/libmediadrm/PluginMetricsReporting.cpp
+++ b/drm/libmediadrm/PluginMetricsReporting.cpp
@@ -34,17 +34,17 @@
status_t reportVendorMetrics(const std::string& metrics,
const String8& name,
const String8& appPackageName) {
- MediaAnalyticsItem analyticsItem(name.c_str());
- analyticsItem.generateSessionID();
+ std::unique_ptr<MediaAnalyticsItem> analyticsItem(MediaAnalyticsItem::create(name.c_str()));
+ analyticsItem->generateSessionID();
std::string app_package_name(appPackageName.c_str(), appPackageName.size());
- analyticsItem.setPkgName(app_package_name);
+ analyticsItem->setPkgName(app_package_name);
if (metrics.size() > 0) {
- analyticsItem.setCString(kSerializedMetricsField, metrics.c_str());
+ analyticsItem->setCString(kSerializedMetricsField, metrics.c_str());
}
- if (!analyticsItem.selfrecord()) {
- ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem.getSessionID());
+ if (!analyticsItem->selfrecord()) {
+ ALOGE("selfrecord() returned false. sessioId %" PRId64, analyticsItem->getSessionID());
}
return OK;
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index 1558e8b..27bd631 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -65,7 +65,20 @@
*plugin = new ClearKeyCasPlugin(appData, callback);
return OK;
}
-///////////////////////////////////////////////////////////////////////////////
+
+status_t ClearKeyCasFactory::createPlugin(
+ int32_t CA_system_id,
+ void *appData,
+ CasPluginCallbackExt callback,
+ CasPlugin **plugin) {
+ if (!isSystemIdSupported(CA_system_id)) {
+ return BAD_VALUE;
+ }
+
+ *plugin = new ClearKeyCasPlugin(appData, callback);
+ return OK;
+}
+////////////////////////////////////////////////////////////////////////////////
bool ClearKeyDescramblerFactory::isSystemIdSupported(
int32_t CA_system_id) const {
return CA_system_id == sClearKeySystemId;
@@ -88,6 +101,12 @@
ALOGV("CTOR");
}
+ClearKeyCasPlugin::ClearKeyCasPlugin(
+ void *appData, CasPluginCallbackExt callback)
+ : mCallbackExt(callback), mAppData(appData) {
+ ALOGV("CTOR");
+}
+
ClearKeyCasPlugin::~ClearKeyCasPlugin() {
ALOGV("DTOR");
ClearKeySessionLibrary::get()->destroyPlugin(this);
@@ -167,11 +186,30 @@
// Echo the received event to the callback.
// Clear key plugin doesn't use any event, echo'ing for testing only.
if (mCallback != NULL) {
- mCallback((void*)mAppData, event, arg, (uint8_t*)eventData.data(), eventData.size());
+ mCallback((void*)mAppData, event, arg, (uint8_t*)eventData.data(),
+ eventData.size());
+ } else if (mCallbackExt != NULL) {
+ mCallbackExt((void*)mAppData, event, arg, (uint8_t*)eventData.data(),
+ eventData.size(), NULL);
}
return OK;
}
+status_t ClearKeyCasPlugin::sendSessionEvent(
+ const CasSessionId &sessionId, int32_t event,
+ int arg, const CasData &eventData) {
+ ALOGV("sendSessionEvent: sessionId=%s, event=%d, arg=%d",
+ sessionIdToString(sessionId).string(), event, arg);
+ // Echo the received event to the callback.
+ // Clear key plugin doesn't use any event, echo'ing for testing only.
+ if (mCallbackExt != NULL) {
+ mCallbackExt((void*)mAppData, event, arg, (uint8_t*)eventData.data(),
+ eventData.size(), &sessionId);
+ }
+
+ return OK;
+}
+
status_t ClearKeyCasPlugin::provision(const String8 &str) {
ALOGV("provision: provisionString=%s", str.string());
Mutex::Autolock lock(mKeyFetcherLock);
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index 389e172..f48d5b1 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -47,6 +47,11 @@
void *appData,
CasPluginCallback callback,
CasPlugin **plugin) override;
+ virtual status_t createPlugin(
+ int32_t CA_system_id,
+ void *appData,
+ CasPluginCallbackExt callback,
+ CasPlugin **plugin) override;
};
class ClearKeyDescramblerFactory : public DescramblerFactory {
@@ -63,6 +68,7 @@
class ClearKeyCasPlugin : public CasPlugin {
public:
ClearKeyCasPlugin(void *appData, CasPluginCallback callback);
+ ClearKeyCasPlugin(void *appData, CasPluginCallbackExt callback);
virtual ~ClearKeyCasPlugin();
virtual status_t setPrivateData(
@@ -85,6 +91,10 @@
virtual status_t sendEvent(
int32_t event, int32_t arg, const CasData &eventData) override;
+ virtual status_t sendSessionEvent(
+ const CasSessionId &sessionId,
+ int32_t event, int32_t arg, const CasData &eventData) override;
+
virtual status_t provision(const String8 &str) override;
virtual status_t refreshEntitlements(
@@ -94,6 +104,7 @@
Mutex mKeyFetcherLock;
std::unique_ptr<KeyFetcher> mKeyFetcher;
CasPluginCallback mCallback;
+ CasPluginCallbackExt mCallbackExt;
void* mAppData;
};
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.cpp b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
index 8404a83..2964791 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.cpp
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.cpp
@@ -60,6 +60,19 @@
return OK;
}
+status_t MockCasFactory::createPlugin(
+ int32_t CA_system_id,
+ void* /*appData*/,
+ CasPluginCallbackExt /*callback*/,
+ CasPlugin **plugin) {
+ if (!isSystemIdSupported(CA_system_id)) {
+ return BAD_VALUE;
+ }
+
+ *plugin = new MockCasPlugin();
+ return OK;
+}
+
///////////////////////////////////////////////////////////////////////////////
bool MockDescramblerFactory::isSystemIdSupported(int32_t CA_system_id) const {
@@ -170,6 +183,16 @@
return OK;
}
+status_t MockCasPlugin::sendSessionEvent(
+ const CasSessionId &sessionId, int32_t event,
+ int /*arg*/, const CasData& /*eventData*/) {
+ ALOGV("sendSessionEvent: sessionId=%s, event=%d",
+ arrayToString(sessionId).string(), event);
+ Mutex::Autolock lock(mLock);
+
+ return OK;
+}
+
status_t MockCasPlugin::provision(const String8 &str) {
ALOGV("provision: provisionString=%s", str.string());
Mutex::Autolock lock(mLock);
diff --git a/drm/mediacas/plugins/mock/MockCasPlugin.h b/drm/mediacas/plugins/mock/MockCasPlugin.h
index 8106990..74b540c 100644
--- a/drm/mediacas/plugins/mock/MockCasPlugin.h
+++ b/drm/mediacas/plugins/mock/MockCasPlugin.h
@@ -42,6 +42,11 @@
void *appData,
CasPluginCallback callback,
CasPlugin **plugin) override;
+ virtual status_t createPlugin(
+ int32_t CA_system_id,
+ void *appData,
+ CasPluginCallbackExt callback,
+ CasPlugin **plugin) override;
};
class MockDescramblerFactory : public DescramblerFactory {
@@ -80,7 +85,11 @@
virtual status_t sendEvent(
int32_t event, int32_t arg, const CasData &eventData) override;
- virtual status_t provision(const String8 &str) override;
+ virtual status_t sendSessionEvent(
+ const CasSessionId &sessionId,
+ int32_t event, int32_t arg, const CasData &eventData) override;
+
+ virtual status_t provision(const String8 &str) override;
virtual status_t refreshEntitlements(
int32_t refreshType, const CasData &refreshData) override;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/Android.bp b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
index b44a6c7..e91e918 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/hidl/Android.bp
@@ -14,8 +14,8 @@
// limitations under the License.
//
-cc_binary {
- name: "android.hardware.drm@1.2-service.clearkey",
+cc_defaults {
+ name: "clearkey_service_defaults",
vendor: true,
srcs: [
@@ -33,13 +33,11 @@
"MemoryFileSystem.cpp",
"Session.cpp",
"SessionLibrary.cpp",
- "service.cpp",
],
relative_install_path: "hw",
cflags: ["-Wall", "-Werror"],
- init_rc: ["android.hardware.drm@1.2-service.clearkey.rc"],
shared_libs: [
"android.hardware.drm@1.0",
@@ -80,3 +78,16 @@
},
srcs: ["protos/DeviceFiles.proto"],
}
+cc_binary {
+ name: "android.hardware.drm@1.2-service.clearkey",
+ defaults: ["clearkey_service_defaults"],
+ srcs: ["service.cpp"],
+ init_rc: ["android.hardware.drm@1.2-service.clearkey.rc"],
+}
+cc_binary {
+ name: "android.hardware.drm@1.2-service-lazy.clearkey",
+ overrides: ["android.hardware.drm@1.2-service.clearkey"],
+ defaults: ["clearkey_service_defaults"],
+ srcs: ["serviceLazy.cpp"],
+ init_rc: ["android.hardware.drm@1.2-service-lazy.clearkey.rc"],
+}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc
new file mode 100644
index 0000000..9afd3d7
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service-lazy.clearkey.rc
@@ -0,0 +1,14 @@
+service vendor.drm-clearkey-hal-1-2 /vendor/bin/hw/android.hardware.drm@1.2-service-lazy.clearkey
+ interface android.hardware.drm@1.0::ICryptoFactory clearkey
+ interface android.hardware.drm@1.0::IDrmFactory clearkey
+ interface android.hardware.drm@1.1::ICryptoFactory clearkey
+ interface android.hardware.drm@1.1::IDrmFactory clearkey
+ interface android.hardware.drm@1.2::ICryptoFactory clearkey
+ interface android.hardware.drm@1.2::IDrmFactory clearkey
+ disabled
+ oneshot
+ class hal
+ user media
+ group media mediadrm
+ ioprio rt 4
+ writepid /dev/cpuset/foreground/tasks
diff --git a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
index ac184f7..5ba669d 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
+++ b/drm/mediadrm/plugins/clearkey/hidl/android.hardware.drm@1.2-service.clearkey.rc
@@ -1,4 +1,10 @@
service vendor.drm-clearkey-hal-1-2 /vendor/bin/hw/android.hardware.drm@1.2-service.clearkey
+ interface android.hardware.drm@1.0::ICryptoFactory clearkey
+ interface android.hardware.drm@1.0::IDrmFactory clearkey
+ interface android.hardware.drm@1.1::ICryptoFactory clearkey
+ interface android.hardware.drm@1.1::IDrmFactory clearkey
+ interface android.hardware.drm@1.2::ICryptoFactory clearkey
+ interface android.hardware.drm@1.2::IDrmFactory clearkey
class hal
user media
group media mediadrm
diff --git a/drm/mediadrm/plugins/clearkey/hidl/service.cpp b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
index 4ca31f3..b39ea01 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/service.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/service.cpp
@@ -13,13 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "android.hardware.drm@1.2-service.clearkey"
-
#include <CryptoFactory.h>
#include <DrmFactory.h>
#include <android-base/logging.h>
#include <binder/ProcessState.h>
+#include <hidl/HidlLazyUtils.h>
#include <hidl/HidlTransportSupport.h>
using ::android::hardware::configureRpcThreadpool;
@@ -31,14 +30,7 @@
using android::hardware::drm::V1_2::clearkey::CryptoFactory;
using android::hardware::drm::V1_2::clearkey::DrmFactory;
-
int main(int /* argc */, char** /* argv */) {
- ALOGD("android.hardware.drm@1.2-service.clearkey starting...");
-
- // The DRM HAL may communicate to other vendor components via
- // /dev/vndbinder
- android::ProcessState::initWithDriver("/dev/vndbinder");
-
sp<IDrmFactory> drmFactory = new DrmFactory;
sp<ICryptoFactory> cryptoFactory = new CryptoFactory;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
new file mode 100644
index 0000000..99fd883
--- /dev/null
+++ b/drm/mediadrm/plugins/clearkey/hidl/serviceLazy.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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 <CryptoFactory.h>
+#include <DrmFactory.h>
+
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlLazyUtils.h>
+#include <hidl/HidlTransportSupport.h>
+
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::sp;
+
+using android::hardware::drm::V1_2::ICryptoFactory;
+using android::hardware::drm::V1_2::IDrmFactory;
+using android::hardware::drm::V1_2::clearkey::CryptoFactory;
+using android::hardware::drm::V1_2::clearkey::DrmFactory;
+using android::hardware::LazyServiceRegistrar;
+
+int main(int /* argc */, char** /* argv */) {
+ sp<IDrmFactory> drmFactory = new DrmFactory;
+ sp<ICryptoFactory> cryptoFactory = new CryptoFactory;
+
+ configureRpcThreadpool(8, true /* callerWillJoin */);
+
+ // Setup hwbinder service
+ LazyServiceRegistrar serviceRegistrar;
+
+ // Setup hwbinder service
+ CHECK_EQ(serviceRegistrar.registerService(drmFactory, "clearkey"), android::NO_ERROR)
+ << "Failed to register Clearkey Factory HAL";
+ CHECK_EQ(serviceRegistrar.registerService(cryptoFactory, "clearkey"), android::NO_ERROR)
+ << "Failed to register Clearkey Crypto HAL";
+
+ joinRpcThreadpool();
+}
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index f05c84b..10d8b13 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -19,7 +19,8 @@
libnbaio \
libnblog \
libsoundtriggerservice \
- libutils
+ libutils \
+ libvibrator
# TODO oboeservice is the old folder name for aaudioservice. It will be changed.
LOCAL_C_INCLUDES := \
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index cf06623..6ddb9ff 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -216,7 +216,7 @@
};
uint64_t mbs = uint64_t((size.v.width + 15) / 16) * ((size.v.height + 15) / 16);
- float mbsPerSec = float(mbs) / frameRate.v.value;
+ float mbsPerSec = float(mbs) * frameRate.v.value;
// Check if the supplied level meets the MB / bitrate requirements. If
// not, update the level with the lowest level meeting the requirements.
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 23939b5..0357115 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -180,6 +180,7 @@
kParamIndexPictureTypeMask,
kParamIndexPictureType,
+ kParamIndexHdr10PlusMetadata,
/* ------------------------------------ video components ------------------------------------ */
@@ -194,7 +195,6 @@
kParamIndexLayerIndex,
kParamIndexLayerCount,
kParamIndexIntraRefresh,
- kParamIndexHdr10PlusMetadata,
/* ------------------------------------ image components ------------------------------------ */
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index c5ad6a0..d0296a5 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -8,8 +8,10 @@
srcs: [
"Component.cpp",
+ "ComponentInterface.cpp",
"ComponentStore.cpp",
"Configurable.cpp",
+ "InputBufferManager.cpp",
"InputSurface.cpp",
"InputSurfaceConnection.cpp",
"types.cpp",
diff --git a/media/codec2/hidl/1.0/utils/Component.cpp b/media/codec2/hidl/1.0/utils/Component.cpp
index 5ae1972..0473b57 100644
--- a/media/codec2/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hidl/1.0/utils/Component.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,11 +18,11 @@
#define LOG_TAG "Codec2-Component"
#include <android-base/logging.h>
-#include <C2PlatformSupport.h>
#include <codec2/hidl/1.0/Component.h>
#include <codec2/hidl/1.0/ComponentStore.h>
-#include <codec2/hidl/1.0/types.h>
+#include <codec2/hidl/1.0/InputBufferManager.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
#include <hidl/HidlBinderSupport.h>
#include <utils/Timers.h>
@@ -42,281 +42,6 @@
using namespace ::android;
-namespace /* unnamed */ {
-
-// Implementation of ConfigurableC2Intf based on C2ComponentInterface
-struct CompIntf : public ConfigurableC2Intf {
- CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
- ConfigurableC2Intf(intf->getName()),
- mIntf(intf) {
- }
-
- virtual c2_status_t config(
- const std::vector<C2Param*>& params,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures
- ) override {
- ALOGV("config");
- return mIntf->config_vb(params, mayBlock, failures);
- }
-
- virtual c2_status_t query(
- const std::vector<C2Param::Index>& indices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const params
- ) const override {
- ALOGV("query");
- return mIntf->query_vb({}, indices, mayBlock, params);
- }
-
- virtual c2_status_t querySupportedParams(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
- ) const override {
- ALOGV("querySupportedParams");
- return mIntf->querySupportedParams_nb(params);
- }
-
- virtual c2_status_t querySupportedValues(
- std::vector<C2FieldSupportedValuesQuery>& fields,
- c2_blocking_t mayBlock) const override {
- ALOGV("querySupportedValues");
- return mIntf->querySupportedValues_vb(fields, mayBlock);
- }
-
-protected:
- std::shared_ptr<C2ComponentInterface> mIntf;
-};
-
-} // unnamed namespace
-
-// InputBufferManager
-// ==================
-//
-// InputBufferManager presents a way to track and untrack input buffers in this
-// (codec) process and send a notification to a listener, possibly in a
-// different process, when a tracked buffer no longer has any references in this
-// process. (In fact, this class would work for listeners in the same process
-// too, but the optimization discussed below will not be beneficial.)
-//
-// InputBufferManager holds a collection of records representing tracked buffers
-// and their callback listeners. Conceptually, one record is a triple (listener,
-// frameIndex, bufferIndex) where
-//
-// - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer.
-// - listener is of type IComponentListener. Its onFramesRendered() function
-// will be called after the associated buffer dies. The argument of
-// onFramesRendered() is a list of RenderedFrame objects, each of which has
-// the following members:
-//
-// uint64_t bufferQueueId
-// int32_t slotId
-// int64_t timestampNs
-//
-// When a tracked buffer associated to the triple (listener, frameIndex,
-// bufferIndex) goes out of scope, listener->onFramesRendered() will be called
-// with a RenderedFrame object whose members are set as follows:
-//
-// bufferQueueId = frameIndex
-// slotId = ~bufferIndex
-// timestampNs = systemTime() at the time of notification
-//
-// The reason for the bitwise negation of bufferIndex is that onFramesRendered()
-// may be used for a different purpose when slotId is non-negative (which is a
-// more general use case).
-//
-// IPC Optimization
-// ----------------
-//
-// Since onFramesRendered() generally is an IPC call, InputBufferManager tries
-// not to call it too often. There is a mechanism to guarantee that any two
-// calls to the same listener are at least kNotificationPeriodNs nanoseconds
-// apart.
-//
-struct InputBufferManager {
- // The minimum time period between IPC calls to notify the client about the
- // destruction of input buffers.
- static constexpr nsecs_t kNotificationPeriodNs = 1000000;
-
- // Track all buffers in a C2FrameData object.
- //
- // input (C2FrameData) has the following two members that are of interest:
- //
- // C2WorkOrdinal ordinal
- // vector<shared_ptr<C2Buffer>> buffers
- //
- // Calling registerFrameData(listener, input) will register multiple
- // triples (, frameIndex, bufferIndex) where frameIndex is equal to
- // input.ordinal.frameIndex and bufferIndex runs through the indices of
- // input.buffers such that input.buffers[bufferIndex] is not null.
- //
- // This should be called from queue().
- static void registerFrameData(
- const sp<IComponentListener>& listener,
- const C2FrameData& input);
-
- // Untrack all buffers in a C2FrameData object.
- //
- // Calling unregisterFrameData(listener, input) will unregister and remove
- // pending notifications for all triples (l, fi, bufferIndex) such that
- // l = listener and fi = input.ordinal.frameIndex.
- //
- // This should be called from onWorkDone() and flush().
- static void unregisterFrameData(
- const wp<IComponentListener>& listener,
- const C2FrameData& input);
-
- // Untrack all buffers associated to a given listener.
- //
- // Calling unregisterFrameData(listener) will unregister and remove
- // pending notifications for all triples (l, frameIndex, bufferIndex) such
- // that l = listener.
- //
- // This should be called when the component cleans up all input buffers,
- // i.e., when reset(), release(), stop() or ~Component() is called.
- static void unregisterFrameData(
- const wp<IComponentListener>& listener);
-
-private:
- void _registerFrameData(
- const sp<IComponentListener>& listener,
- const C2FrameData& input);
- void _unregisterFrameData(
- const wp<IComponentListener>& listener,
- const C2FrameData& input);
- void _unregisterFrameData(
- const wp<IComponentListener>& listener);
-
- // The callback function tied to C2Buffer objects.
- //
- // Note: This function assumes that sInstance is the only instance of this
- // class.
- static void onBufferDestroyed(const C2Buffer* buf, void* arg);
- void _onBufferDestroyed(const C2Buffer* buf, void* arg);
-
- // Comparison operator for weak pointers.
- struct CompareWeakComponentListener {
- constexpr bool operator()(
- const wp<IComponentListener>& x,
- const wp<IComponentListener>& y) const {
- return x.get_refs() < y.get_refs();
- }
- };
-
- // Persistent data to be passed as "arg" in onBufferDestroyed().
- // This is essentially the triple (listener, frameIndex, bufferIndex) plus a
- // weak pointer to the C2Buffer object.
- //
- // Note that the "key" is bufferIndex according to operator<(). This is
- // designed to work with TrackedBuffersMap defined below.
- struct TrackedBuffer {
- wp<IComponentListener> listener;
- uint64_t frameIndex;
- size_t bufferIndex;
- std::weak_ptr<C2Buffer> buffer;
- TrackedBuffer(const wp<IComponentListener>& listener,
- uint64_t frameIndex,
- size_t bufferIndex,
- const std::shared_ptr<C2Buffer>& buffer)
- : listener(listener),
- frameIndex(frameIndex),
- bufferIndex(bufferIndex),
- buffer(buffer) {}
- TrackedBuffer(const TrackedBuffer&) = default;
- bool operator<(const TrackedBuffer& other) const {
- return bufferIndex < other.bufferIndex;
- }
- };
-
- // Map: listener -> frameIndex -> set<TrackedBuffer>.
- // Essentially, this is used to store triples (listener, frameIndex,
- // bufferIndex) that's searchable by listener and (listener, frameIndex).
- // However, the value of the innermost map is TrackedBuffer, which also
- // contains an extra copy of listener and frameIndex. This is needed
- // because onBufferDestroyed() needs to know listener and frameIndex too.
- typedef std::map<wp<IComponentListener>,
- std::map<uint64_t,
- std::set<TrackedBuffer>>,
- CompareWeakComponentListener> TrackedBuffersMap;
-
- // Storage for pending (unsent) death notifications for one listener.
- // Each pair in member named "indices" are (frameIndex, bufferIndex) from
- // the (listener, frameIndex, bufferIndex) triple.
- struct DeathNotifications {
-
- // The number of pending notifications for this listener.
- // count may be 0, in which case the DeathNotifications object will
- // remain valid for only a small period (kNotificationPeriodNs
- // nanoseconds).
- size_t count;
-
- // The timestamp of the most recent callback on this listener. This is
- // used to guarantee that callbacks do not occur too frequently, and
- // also to trigger expiration of a DeathNotifications object that has
- // count = 0.
- nsecs_t lastSentNs;
-
- // Map: frameIndex -> vector of bufferIndices
- // This is essentially a collection of (framdeIndex, bufferIndex).
- std::map<uint64_t, std::vector<size_t>> indices;
-
- DeathNotifications()
- : count(0),
- lastSentNs(systemTime() - kNotificationPeriodNs),
- indices() {}
- };
-
- // Mutex for the management of all input buffers.
- std::mutex mMutex;
-
- // Tracked input buffers.
- TrackedBuffersMap mTrackedBuffersMap;
-
- // Death notifications to be sent.
- //
- // A DeathNotifications object is associated to each listener. An entry in
- // this map will be removed if its associated DeathNotifications has count =
- // 0 and lastSentNs < systemTime() - kNotificationPeriodNs.
- std::map<wp<IComponentListener>, DeathNotifications> mDeathNotifications;
-
- // Condition variable signaled when an entry is added to mDeathNotifications.
- std::condition_variable mOnBufferDestroyed;
-
- // Notify the clients about buffer destructions.
- // Return false if all destructions have been notified.
- // Return true and set timeToRetry to the duration to wait for before
- // retrying if some destructions have not been notified.
- bool processNotifications(nsecs_t* timeToRetryNs);
-
- // Main function for the input buffer manager thread.
- void main();
-
- // The thread that manages notifications.
- //
- // Note: This variable is declared last so its initialization will happen
- // after all other member variables have been initialized.
- std::thread mMainThread;
-
- // Private constructor.
- InputBufferManager();
-
- // The only instance of this class.
- static InputBufferManager& getInstance();
-
-};
-
-// ComponentInterface
-ComponentInterface::ComponentInterface(
- const std::shared_ptr<C2ComponentInterface>& intf,
- const sp<ComponentStore>& store) :
- Configurable(new CachedConfigurable(std::make_unique<CompIntf>(intf))),
- mInterface(intf) {
- mInit = init(store.get());
-}
-
-c2_status_t ComponentInterface::status() const {
- return mInit;
-}
-
// ComponentListener wrapper
struct Component::Listener : public C2Component::Listener {
@@ -328,12 +53,12 @@
virtual void onError_nb(
std::weak_ptr<C2Component> /* c2component */,
uint32_t errorCode) override {
- ALOGV("onError");
sp<IComponentListener> listener = mListener.promote();
if (listener) {
Return<void> transStatus = listener->onError(Status::OK, errorCode);
if (!transStatus.isOk()) {
- ALOGE("onError -- transaction failed.");
+ LOG(ERROR) << "Component::Listener::onError_nb -- "
+ << "transaction failed.";
}
}
}
@@ -342,7 +67,6 @@
std::weak_ptr<C2Component> /* c2component */,
std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
) override {
- ALOGV("onTripped");
sp<IComponentListener> listener = mListener.promote();
if (listener) {
hidl_vec<SettingResult> settingResults(c2settingResult.size());
@@ -350,8 +74,7 @@
for (const std::shared_ptr<C2SettingResult> &c2result :
c2settingResult) {
if (c2result) {
- if (objcpy(&settingResults[ix++], *c2result) !=
- Status::OK) {
+ if (!objcpy(&settingResults[ix++], *c2result)) {
break;
}
}
@@ -359,7 +82,8 @@
settingResults.resize(ix);
Return<void> transStatus = listener->onTripped(settingResults);
if (!transStatus.isOk()) {
- ALOGE("onTripped -- transaction failed.");
+ LOG(ERROR) << "Component::Listener::onTripped_nb -- "
+ << "transaction failed.";
}
}
}
@@ -367,7 +91,6 @@
virtual void onWorkDone_nb(
std::weak_ptr<C2Component> /* c2component */,
std::list<std::unique_ptr<C2Work>> c2workItems) override {
- ALOGV("onWorkDone");
for (const std::unique_ptr<C2Work>& work : c2workItems) {
if (work) {
if (work->worklets.empty()
@@ -385,15 +108,16 @@
WorkBundle workBundle;
sp<Component> strongComponent = mComponent.promote();
- if (objcpy(&workBundle, c2workItems, strongComponent ?
- &strongComponent->mBufferPoolSender : nullptr)
- != Status::OK) {
- ALOGE("onWorkDone() received corrupted work items.");
+ if (!objcpy(&workBundle, c2workItems, strongComponent ?
+ &strongComponent->mBufferPoolSender : nullptr)) {
+ LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+ << "received corrupted work items.";
return;
}
Return<void> transStatus = listener->onWorkDone(workBundle);
if (!transStatus.isOk()) {
- ALOGE("onWorkDone -- transaction failed.");
+ LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+ << "transaction failed.";
return;
}
yieldBufferQueueBlocks(c2workItems, true);
@@ -405,23 +129,86 @@
wp<IComponentListener> mListener;
};
+// Component::Sink
+struct Component::Sink : public IInputSink {
+ std::shared_ptr<Component> mComponent;
+ sp<IConfigurable> mConfigurable;
+
+ virtual Return<Status> queue(const WorkBundle& workBundle) override {
+ return mComponent->queue(workBundle);
+ }
+
+ virtual Return<sp<IConfigurable>> getConfigurable() override {
+ return mConfigurable;
+ }
+
+ Sink(const std::shared_ptr<Component>& component);
+ virtual ~Sink() override;
+
+ // Process-wide map: Component::Sink -> C2Component.
+ static std::mutex sSink2ComponentMutex;
+ static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component;
+
+ static std::shared_ptr<C2Component> findLocalComponent(
+ const sp<IInputSink>& sink);
+};
+
+std::mutex
+ Component::Sink::sSink2ComponentMutex{};
+std::map<IInputSink*, std::weak_ptr<C2Component>>
+ Component::Sink::sSink2Component{};
+
+Component::Sink::Sink(const std::shared_ptr<Component>& component)
+ : mComponent{component},
+ mConfigurable{[&component]() -> sp<IConfigurable> {
+ Return<sp<IComponentInterface>> ret1 = component->getInterface();
+ if (!ret1.isOk()) {
+ LOG(ERROR) << "Sink::Sink -- component's transaction failed.";
+ return nullptr;
+ }
+ Return<sp<IConfigurable>> ret2 =
+ static_cast<sp<IComponentInterface>>(ret1)->
+ getConfigurable();
+ if (!ret2.isOk()) {
+ LOG(ERROR) << "Sink::Sink -- interface's transaction failed.";
+ return nullptr;
+ }
+ return static_cast<sp<IConfigurable>>(ret2);
+ }()} {
+ std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+ sSink2Component.emplace(this, component->mComponent);
+}
+
+Component::Sink::~Sink() {
+ std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+ sSink2Component.erase(this);
+}
+
+std::shared_ptr<C2Component> Component::Sink::findLocalComponent(
+ const sp<IInputSink>& sink) {
+ std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+ auto i = sSink2Component.find(sink.get());
+ if (i == sSink2Component.end()) {
+ return nullptr;
+ }
+ return i->second.lock();
+}
+
// Component
Component::Component(
const std::shared_ptr<C2Component>& component,
const sp<IComponentListener>& listener,
const sp<ComponentStore>& store,
const sp<::android::hardware::media::bufferpool::V2_0::
- IClientManager>& clientPoolManager) :
- Configurable(new CachedConfigurable(
- std::make_unique<CompIntf>(component->intf()))),
- mComponent(component),
- mInterface(component->intf()),
- mListener(listener),
- mStore(store),
- mBufferPoolSender(clientPoolManager) {
+ IClientManager>& clientPoolManager)
+ : mComponent{component},
+ mInterface{new ComponentInterface(component->intf(), store.get())},
+ mListener{listener},
+ mStore{store},
+ mBufferPoolSender{clientPoolManager} {
// Retrieve supported parameters from store
// TODO: We could cache this per component/interface type
- mInit = init(store.get());
+ mInit = mInterface->status();
}
c2_status_t Component::status() const {
@@ -430,11 +217,9 @@
// Methods from ::android::hardware::media::c2::V1_0::IComponent
Return<Status> Component::queue(const WorkBundle& workBundle) {
- ALOGV("queue -- converting input");
std::list<std::unique_ptr<C2Work>> c2works;
- if (objcpy(&c2works, workBundle) != C2_OK) {
- ALOGV("queue -- corrupted");
+ if (!objcpy(&c2works, workBundle)) {
return Status::CORRUPTED;
}
@@ -446,13 +231,11 @@
}
}
- ALOGV("queue -- calling");
return static_cast<Status>(mComponent->queue_nb(&c2works));
}
Return<void> Component::flush(flush_cb _hidl_cb) {
std::list<std::unique_ptr<C2Work>> c2flushedWorks;
- ALOGV("flush -- calling");
c2_status_t c2res = mComponent->flush_sm(
C2Component::FLUSH_COMPONENT,
&c2flushedWorks);
@@ -473,8 +256,9 @@
WorkBundle flushedWorkBundle;
Status res = static_cast<Status>(c2res);
if (c2res == C2_OK) {
- ALOGV("flush -- converting output");
- res = objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender);
+ if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
+ res = Status::CORRUPTED;
+ }
}
_hidl_cb(res, flushedWorkBundle);
yieldBufferQueueBlocks(c2flushedWorks, true);
@@ -482,7 +266,6 @@
}
Return<Status> Component::drain(bool withEos) {
- ALOGV("drain");
return static_cast<Status>(mComponent->drain_nb(withEos ?
C2Component::DRAIN_COMPONENT_WITH_EOS :
C2Component::DRAIN_COMPONENT_NO_EOS));
@@ -512,14 +295,39 @@
return Status::OK;
}
-Return<Status> Component::connectToOmxInputSurface(
+Return<void> Component::connectToInputSurface(
+ const sp<IInputSurface>& inputSurface,
+ connectToInputSurface_cb _hidl_cb) {
+ sp<Sink> sink;
+ {
+ std::lock_guard<std::mutex> lock(mSinkMutex);
+ if (!mSink) {
+ mSink = new Sink(shared_from_this());
+ }
+ sink = mSink;
+ }
+ Status status;
+ sp<IInputSurfaceConnection> connection;
+ auto transStatus = inputSurface->connect(sink,
+ [&status, &connection](Status s,
+ const sp<IInputSurfaceConnection>& c) {
+ status = s;
+ connection = c;
+ }
+ );
+ _hidl_cb(status, connection);
+ return Void();
+}
+
+Return<void> Component::connectToOmxInputSurface(
const sp<HGraphicBufferProducer>& producer,
const sp<::android::hardware::media::omx::V1_0::
- IGraphicBufferSource>& source) {
- // TODO implement
+ IGraphicBufferSource>& source,
+ connectToOmxInputSurface_cb _hidl_cb) {
(void)producer;
(void)source;
- return Status::OMITTED;
+ (void)_hidl_cb;
+ return Void();
}
Return<Status> Component::disconnectFromInputSurface() {
@@ -530,11 +338,12 @@
namespace /* unnamed */ {
struct BlockPoolIntf : public ConfigurableC2Intf {
- BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool) :
- ConfigurableC2Intf("C2BlockPool:" +
- (pool ? std::to_string(pool->getLocalId()) :
- "null")),
- mPool(pool) {
+ BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
+ : ConfigurableC2Intf{
+ "C2BlockPool:" +
+ (pool ? std::to_string(pool->getLocalId()) : "null"),
+ 0},
+ mPool{pool} {
}
virtual c2_status_t config(
@@ -613,18 +422,15 @@
}
Return<Status> Component::start() {
- ALOGV("start");
return static_cast<Status>(mComponent->start());
}
Return<Status> Component::stop() {
- ALOGV("stop");
InputBufferManager::unregisterFrameData(mListener);
return static_cast<Status>(mComponent->stop());
}
Return<Status> Component::reset() {
- ALOGV("reset");
Status status = static_cast<Status>(mComponent->reset());
{
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
@@ -635,7 +441,6 @@
}
Return<Status> Component::release() {
- ALOGV("release");
Status status = static_cast<Status>(mComponent->release());
{
std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
@@ -645,8 +450,13 @@
return status;
}
-void Component::setLocalId(const Component::LocalId& localId) {
- mLocalId = localId;
+Return<sp<IComponentInterface>> Component::getInterface() {
+ return sp<IComponentInterface>(mInterface);
+}
+
+std::shared_ptr<C2Component> Component::findLocalComponent(
+ const sp<IInputSink>& sink) {
+ return Component::Sink::findLocalComponent(sink);
}
void Component::initListener(const sp<Component>& self) {
@@ -660,395 +470,7 @@
Component::~Component() {
InputBufferManager::unregisterFrameData(mListener);
- mStore->reportComponentDeath(mLocalId);
-}
-
-Component::InterfaceKey::InterfaceKey(const sp<IComponent>& component) {
- isRemote = component->isRemote();
- if (isRemote) {
- remote = ::android::hardware::toBinder(component);
- } else {
- local = component;
- }
-}
-
-// InputBufferManager implementation
-
-constexpr nsecs_t InputBufferManager::kNotificationPeriodNs;
-
-void InputBufferManager::registerFrameData(
- const sp<IComponentListener>& listener,
- const C2FrameData& input) {
- getInstance()._registerFrameData(listener, input);
-}
-
-void InputBufferManager::unregisterFrameData(
- const wp<IComponentListener>& listener,
- const C2FrameData& input) {
- getInstance()._unregisterFrameData(listener, input);
-}
-
-void InputBufferManager::unregisterFrameData(
- const wp<IComponentListener>& listener) {
- getInstance()._unregisterFrameData(listener);
-}
-
-void InputBufferManager::_registerFrameData(
- const sp<IComponentListener>& listener,
- const C2FrameData& input) {
- uint64_t frameIndex = input.ordinal.frameIndex.peeku();
- ALOGV("InputBufferManager::_registerFrameData called "
- "(listener @ %p, frameIndex = %llu)",
- listener.get(),
- static_cast<long long unsigned>(frameIndex));
- std::lock_guard<std::mutex> lock(mMutex);
-
- std::set<TrackedBuffer> &bufferIds =
- mTrackedBuffersMap[listener][frameIndex];
-
- for (size_t i = 0; i < input.buffers.size(); ++i) {
- if (!input.buffers[i]) {
- ALOGV("InputBufferManager::_registerFrameData: "
- "Input buffer at index %zu is null", i);
- continue;
- }
- const TrackedBuffer &bufferId =
- *bufferIds.emplace(listener, frameIndex, i, input.buffers[i]).
- first;
-
- c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
- onBufferDestroyed,
- const_cast<void*>(reinterpret_cast<const void*>(&bufferId)));
- if (status != C2_OK) {
- ALOGD("InputBufferManager: registerOnDestroyNotify failed "
- "(listener @ %p, frameIndex = %llu, bufferIndex = %zu) "
- "=> %s (%d)",
- listener.get(),
- static_cast<unsigned long long>(frameIndex),
- i,
- asString(status), static_cast<int>(status));
- }
- }
-
- mDeathNotifications.emplace(listener, DeathNotifications());
-}
-
-// Remove a pair (listener, frameIndex) from mTrackedBuffersMap and
-// mDeathNotifications. This implies all bufferIndices are removed.
-//
-// This is called from onWorkDone() and flush().
-void InputBufferManager::_unregisterFrameData(
- const wp<IComponentListener>& listener,
- const C2FrameData& input) {
- uint64_t frameIndex = input.ordinal.frameIndex.peeku();
- ALOGV("InputBufferManager::_unregisterFrameData called "
- "(listener @ %p, frameIndex = %llu)",
- listener.unsafe_get(),
- static_cast<long long unsigned>(frameIndex));
- std::lock_guard<std::mutex> lock(mMutex);
-
- auto findListener = mTrackedBuffersMap.find(listener);
- if (findListener != mTrackedBuffersMap.end()) {
- std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
- = findListener->second;
- auto findFrameIndex = frameIndex2BufferIds.find(frameIndex);
- if (findFrameIndex != frameIndex2BufferIds.end()) {
- std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
- for (const TrackedBuffer& bufferId : bufferIds) {
- std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
- if (buffer) {
- c2_status_t status = buffer->unregisterOnDestroyNotify(
- onBufferDestroyed,
- const_cast<void*>(
- reinterpret_cast<const void*>(&bufferId)));
- if (status != C2_OK) {
- ALOGD("InputBufferManager: "
- "unregisterOnDestroyNotify failed "
- "(listener @ %p, "
- "frameIndex = %llu, "
- "bufferIndex = %zu) "
- "=> %s (%d)",
- bufferId.listener.unsafe_get(),
- static_cast<unsigned long long>(
- bufferId.frameIndex),
- bufferId.bufferIndex,
- asString(status), static_cast<int>(status));
- }
- }
- }
-
- frameIndex2BufferIds.erase(findFrameIndex);
- if (frameIndex2BufferIds.empty()) {
- mTrackedBuffersMap.erase(findListener);
- }
- }
- }
-
- auto findListenerD = mDeathNotifications.find(listener);
- if (findListenerD != mDeathNotifications.end()) {
- DeathNotifications &deathNotifications = findListenerD->second;
- auto findFrameIndex = deathNotifications.indices.find(frameIndex);
- if (findFrameIndex != deathNotifications.indices.end()) {
- std::vector<size_t> &bufferIndices = findFrameIndex->second;
- deathNotifications.count -= bufferIndices.size();
- deathNotifications.indices.erase(findFrameIndex);
- }
- }
-}
-
-// Remove listener from mTrackedBuffersMap and mDeathNotifications. This implies
-// all frameIndices and bufferIndices are removed.
-//
-// This is called when the component cleans up all input buffers, i.e., when
-// reset(), release(), stop() or ~Component() is called.
-void InputBufferManager::_unregisterFrameData(
- const wp<IComponentListener>& listener) {
- ALOGV("InputBufferManager::_unregisterFrameData called (listener @ %p)",
- listener.unsafe_get());
- std::lock_guard<std::mutex> lock(mMutex);
-
- auto findListener = mTrackedBuffersMap.find(listener);
- if (findListener != mTrackedBuffersMap.end()) {
- std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds =
- findListener->second;
- for (auto findFrameIndex = frameIndex2BufferIds.begin();
- findFrameIndex != frameIndex2BufferIds.end();
- ++findFrameIndex) {
- std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
- for (const TrackedBuffer& bufferId : bufferIds) {
- std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
- if (buffer) {
- c2_status_t status = buffer->unregisterOnDestroyNotify(
- onBufferDestroyed,
- const_cast<void*>(
- reinterpret_cast<const void*>(&bufferId)));
- if (status != C2_OK) {
- ALOGD("InputBufferManager: "
- "unregisterOnDestroyNotify failed "
- "(listener @ %p, "
- "frameIndex = %llu, "
- "bufferIndex = %zu) "
- "=> %s (%d)",
- bufferId.listener.unsafe_get(),
- static_cast<unsigned long long>(bufferId.frameIndex),
- bufferId.bufferIndex,
- asString(status), static_cast<int>(status));
- }
- }
- }
- }
- mTrackedBuffersMap.erase(findListener);
- }
-
- mDeathNotifications.erase(listener);
-}
-
-// Move a buffer from mTrackedBuffersMap to mDeathNotifications.
-// This is called when a registered C2Buffer object is destroyed.
-void InputBufferManager::onBufferDestroyed(const C2Buffer* buf, void* arg) {
- getInstance()._onBufferDestroyed(buf, arg);
-}
-
-void InputBufferManager::_onBufferDestroyed(const C2Buffer* buf, void* arg) {
- if (!buf || !arg) {
- ALOGW("InputBufferManager::_onBufferDestroyed called "
- "with null argument(s) (buf @ %p, arg @ %p)",
- buf, arg);
- return;
- }
- TrackedBuffer id(*reinterpret_cast<TrackedBuffer*>(arg));
- ALOGV("InputBufferManager::_onBufferDestroyed called "
- "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
- id.listener.unsafe_get(),
- static_cast<unsigned long long>(id.frameIndex),
- id.bufferIndex);
-
- std::lock_guard<std::mutex> lock(mMutex);
-
- auto findListener = mTrackedBuffersMap.find(id.listener);
- if (findListener == mTrackedBuffersMap.end()) {
- ALOGD("InputBufferManager::_onBufferDestroyed received "
- "invalid listener "
- "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
- id.listener.unsafe_get(),
- static_cast<unsigned long long>(id.frameIndex),
- id.bufferIndex);
- return;
- }
-
- std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
- = findListener->second;
- auto findFrameIndex = frameIndex2BufferIds.find(id.frameIndex);
- if (findFrameIndex == frameIndex2BufferIds.end()) {
- ALOGD("InputBufferManager::_onBufferDestroyed received "
- "invalid frame index "
- "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
- id.listener.unsafe_get(),
- static_cast<unsigned long long>(id.frameIndex),
- id.bufferIndex);
- return;
- }
-
- std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
- auto findBufferId = bufferIds.find(id);
- if (findBufferId == bufferIds.end()) {
- ALOGD("InputBufferManager::_onBufferDestroyed received "
- "invalid buffer index: "
- "(listener @ %p, frameIndex = %llu, bufferIndex = %zu)",
- id.listener.unsafe_get(),
- static_cast<unsigned long long>(id.frameIndex),
- id.bufferIndex);
- }
-
- bufferIds.erase(findBufferId);
- if (bufferIds.empty()) {
- frameIndex2BufferIds.erase(findFrameIndex);
- if (frameIndex2BufferIds.empty()) {
- mTrackedBuffersMap.erase(findListener);
- }
- }
-
- DeathNotifications &deathNotifications = mDeathNotifications[id.listener];
- deathNotifications.indices[id.frameIndex].emplace_back(id.bufferIndex);
- ++deathNotifications.count;
- mOnBufferDestroyed.notify_one();
-}
-
-// Notify the clients about buffer destructions.
-// Return false if all destructions have been notified.
-// Return true and set timeToRetry to the time point to wait for before
-// retrying if some destructions have not been notified.
-bool InputBufferManager::processNotifications(nsecs_t* timeToRetryNs) {
-
- struct Notification {
- sp<IComponentListener> listener;
- hidl_vec<IComponentListener::RenderedFrame> renderedFrames;
- Notification(const sp<IComponentListener>& l, size_t s)
- : listener(l), renderedFrames(s) {}
- };
- std::list<Notification> notifications;
-
- bool retry = false;
- {
- std::lock_guard<std::mutex> lock(mMutex);
- *timeToRetryNs = kNotificationPeriodNs;
- nsecs_t timeNowNs = systemTime();
- for (auto it = mDeathNotifications.begin();
- it != mDeathNotifications.end(); ) {
- sp<IComponentListener> listener = it->first.promote();
- if (!listener) {
- ++it;
- continue;
- }
- DeathNotifications &deathNotifications = it->second;
-
- nsecs_t timeSinceLastNotifiedNs =
- timeNowNs - deathNotifications.lastSentNs;
- // If not enough time has passed since the last callback, leave the
- // notifications for this listener untouched for now and retry
- // later.
- if (timeSinceLastNotifiedNs < kNotificationPeriodNs) {
- retry = true;
- *timeToRetryNs = std::min(*timeToRetryNs,
- kNotificationPeriodNs - timeSinceLastNotifiedNs);
- ALOGV("InputBufferManager: Notifications for "
- "listener @ %p will be postponed.",
- listener.get());
- ++it;
- continue;
- }
-
- // If enough time has passed since the last notification to this
- // listener but there are currently no pending notifications, the
- // listener can be removed from mDeathNotifications---there is no
- // need to keep track of the last notification time anymore.
- if (deathNotifications.count == 0) {
- it = mDeathNotifications.erase(it);
- continue;
- }
-
- // Create the argument for the callback.
- notifications.emplace_back(listener, deathNotifications.count);
- hidl_vec<IComponentListener::RenderedFrame>& renderedFrames =
- notifications.back().renderedFrames;
- size_t i = 0;
- for (std::pair<const uint64_t, std::vector<size_t>>& p :
- deathNotifications.indices) {
- uint64_t frameIndex = p.first;
- const std::vector<size_t> &bufferIndices = p.second;
- for (const size_t& bufferIndex : bufferIndices) {
- IComponentListener::RenderedFrame &renderedFrame
- = renderedFrames[i++];
- renderedFrame.slotId = ~bufferIndex;
- renderedFrame.bufferQueueId = frameIndex;
- renderedFrame.timestampNs = timeNowNs;
- ALOGV("InputBufferManager: "
- "Sending death notification (listener @ %p, "
- "frameIndex = %llu, bufferIndex = %zu)",
- listener.get(),
- static_cast<long long unsigned>(frameIndex),
- bufferIndex);
- }
- }
-
- // Clear deathNotifications for this listener and set retry to true
- // so processNotifications will be called again. This will
- // guarantee that a listener with no pending notifications will
- // eventually be removed from mDeathNotifications after
- // kNotificationPeriodNs nanoseconds has passed.
- retry = true;
- deathNotifications.indices.clear();
- deathNotifications.count = 0;
- deathNotifications.lastSentNs = timeNowNs;
- ++it;
- }
- }
-
- // Call onFramesRendered outside the lock to avoid deadlock.
- for (const Notification& notification : notifications) {
- if (!notification.listener->onFramesRendered(
- notification.renderedFrames).isOk()) {
- // This may trigger if the client has died.
- ALOGD("InputBufferManager: onFramesRendered transaction failed "
- "(listener @ %p)",
- notification.listener.get());
- }
- }
- if (retry) {
- ALOGV("InputBufferManager: Pending death notifications"
- "will be sent in %lldns.",
- static_cast<long long>(*timeToRetryNs));
- }
- return retry;
-}
-
-void InputBufferManager::main() {
- ALOGV("InputBufferManager: Starting main thread");
- nsecs_t timeToRetryNs;
- while (true) {
- std::unique_lock<std::mutex> lock(mMutex);
- while (mDeathNotifications.empty()) {
- ALOGV("InputBufferManager: Waiting for buffer deaths");
- mOnBufferDestroyed.wait(lock);
- }
- lock.unlock();
- ALOGV("InputBufferManager: Sending buffer death notifications");
- while (processNotifications(&timeToRetryNs)) {
- std::this_thread::sleep_for(
- std::chrono::nanoseconds(timeToRetryNs));
- ALOGV("InputBufferManager: Sending pending death notifications");
- }
- ALOGV("InputBufferManager: No pending death notifications");
- }
-}
-
-InputBufferManager::InputBufferManager()
- : mMainThread(&InputBufferManager::main, this) {
-}
-
-InputBufferManager& InputBufferManager::getInstance() {
- static InputBufferManager instance{};
- return instance;
+ mStore->reportComponentDeath(this);
}
} // namespace utils
diff --git a/media/codec2/hidl/1.0/utils/ComponentInterface.cpp b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
new file mode 100644
index 0000000..39e5357
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-ComponentInterface"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.0/ComponentStore.h>
+
+#include <hidl/HidlBinderSupport.h>
+#include <utils/Timers.h>
+
+#include <C2BqBufferPriv.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+namespace /* unnamed */ {
+
+// Implementation of ConfigurableC2Intf based on C2ComponentInterface
+struct CompIntf : public ConfigurableC2Intf {
+ CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
+ ConfigurableC2Intf{intf->getName(), intf->getId()},
+ mIntf{intf} {
+ }
+
+ virtual c2_status_t config(
+ const std::vector<C2Param*>& params,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures
+ ) override {
+ return mIntf->config_vb(params, mayBlock, failures);
+ }
+
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index>& indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const params
+ ) const override {
+ return mIntf->query_vb({}, indices, mayBlock, params);
+ }
+
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+ ) const override {
+ return mIntf->querySupportedParams_nb(params);
+ }
+
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields,
+ c2_blocking_t mayBlock) const override {
+ return mIntf->querySupportedValues_vb(fields, mayBlock);
+ }
+
+protected:
+ std::shared_ptr<C2ComponentInterface> mIntf;
+};
+
+} // unnamed namespace
+
+// ComponentInterface
+ComponentInterface::ComponentInterface(
+ const std::shared_ptr<C2ComponentInterface>& intf,
+ ComponentStore* store)
+ : mInterface{intf},
+ mConfigurable{new CachedConfigurable(std::make_unique<CompIntf>(intf))} {
+ mInit = mConfigurable->init(store);
+}
+
+c2_status_t ComponentInterface::status() const {
+ return mInit;
+}
+
+Return<sp<IConfigurable>> ComponentInterface::getConfigurable() {
+ return mConfigurable;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
index 9c05014..bb5faa5 100644
--- a/media/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,37 +16,25 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2-ComponentStore"
-#include <log/log.h>
+#include <android-base/logging.h>
#include <codec2/hidl/1.0/ComponentStore.h>
#include <codec2/hidl/1.0/InputSurface.h>
-#include <codec2/hidl/1.0/Component.h>
-#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
#include <codec2/hidl/1.0/types.h>
+#include <android-base/file.h>
#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <utils/Errors.h>
#include <C2PlatformSupport.h>
#include <util/C2InterfaceHelper.h>
-#include <utils/Errors.h>
-
-#include <android-base/file.h>
-
-#ifdef LOG
-#undef LOG
-#endif
-
-#ifdef PLOG
-#undef PLOG
-#endif
-
-#include <android-base/logging.h>
-
+#include <chrono>
+#include <ctime>
+#include <iomanip>
#include <ostream>
#include <sstream>
-#include <iomanip>
namespace android {
namespace hardware {
@@ -62,12 +50,12 @@
namespace /* unnamed */ {
struct StoreIntf : public ConfigurableC2Intf {
- StoreIntf(const std::shared_ptr<C2ComponentStore>& store) :
- ConfigurableC2Intf(store ? store->getName() : ""),
- mStore(store) {
+ StoreIntf(const std::shared_ptr<C2ComponentStore>& store)
+ : ConfigurableC2Intf{store ? store->getName() : "", 0},
+ mStore{store} {
}
- c2_status_t config(
+ virtual c2_status_t config(
const std::vector<C2Param*> ¶ms,
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2SettingResult>> *const failures
@@ -80,7 +68,7 @@
return mStore->config_sm(params, failures);
}
- c2_status_t query(
+ virtual c2_status_t query(
const std::vector<C2Param::Index> &indices,
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2Param>> *const params) const override {
@@ -92,13 +80,13 @@
return mStore->query_sm({}, indices, params);
}
- c2_status_t querySupportedParams(
+ virtual c2_status_t querySupportedParams(
std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
) const override {
return mStore->querySupportedParams_nb(params);
}
- c2_status_t querySupportedValues(
+ virtual c2_status_t querySupportedValues(
std::vector<C2FieldSupportedValuesQuery> &fields,
c2_blocking_t mayBlock) const override {
// Assume all params are blocking
@@ -115,9 +103,9 @@
} // unnamed namespace
-ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store) :
- Configurable(new CachedConfigurable(std::make_unique<StoreIntf>(store))),
- mStore(store) {
+ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
+ : mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+ mStore{store} {
std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
SetPreferredCodec2ComponentStore(store);
@@ -126,7 +114,11 @@
mParamReflector = mStore->getParamReflector();
// Retrieve supported parameters from store
- mInit = init(this);
+ mInit = mConfigurable->init(this);
+}
+
+c2_status_t ComponentStore::status() const {
+ return mInit;
}
c2_status_t ComponentStore::validateSupportedParams(
@@ -172,19 +164,15 @@
component = new Component(c2component, listener, this, pool);
if (!component) {
status = Status::CORRUPTED;
- } else if (component->status() != C2_OK) {
- status = static_cast<Status>(component->status());
} else {
- component->initListener(component);
+ reportComponentBirth(component.get());
if (component->status() != C2_OK) {
status = static_cast<Status>(component->status());
} else {
- std::lock_guard<std::mutex> lock(mComponentRosterMutex);
- component->setLocalId(
- mComponentRoster.emplace(
- Component::InterfaceKey(component),
- c2component)
- .first);
+ component->initListener(component);
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ }
}
}
}
@@ -202,7 +190,7 @@
onInterfaceLoaded(c2interface);
interface = new ComponentInterface(c2interface, this);
}
- _hidl_cb((Status)res, interface);
+ _hidl_cb(static_cast<Status>(res), interface);
return Void();
}
@@ -213,27 +201,35 @@
size_t ix = 0;
for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
if (c2trait) {
- objcpy(&traits[ix++], *c2trait);
+ if (objcpy(&traits[ix], *c2trait)) {
+ ++ix;
+ } else {
+ break;
+ }
}
}
traits.resize(ix);
- _hidl_cb(traits);
+ _hidl_cb(Status::OK, traits);
return Void();
}
-Return<sp<IInputSurface>> ComponentStore::createInputSurface() {
+Return<void> ComponentStore::createInputSurface(createInputSurface_cb _hidl_cb) {
sp<GraphicBufferSource> source = new GraphicBufferSource();
if (source->initCheck() != OK) {
- return nullptr;
+ _hidl_cb(Status::CORRUPTED, nullptr);
+ return Void();
}
typedef ::android::hardware::graphics::bufferqueue::V1_0::
IGraphicBufferProducer HGbp;
typedef ::android::TWGraphicBufferProducer<HGbp> B2HGbp;
- return new InputSurface(
+ sp<InputSurface> inputSurface = new InputSurface(
this,
std::make_shared<C2ReflectorHelper>(),
new B2HGbp(source->getIGraphicBufferProducer()),
source);
+ _hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
+ inputSurface);
+ return Void();
}
void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
@@ -265,15 +261,25 @@
mUnsupportedStructDescriptors.emplace(coreIndex);
} else {
mStructDescriptors.insert({ coreIndex, structDesc });
- objcpy(&descriptors[dstIx++], *structDesc);
- continue;
+ if (objcpy(&descriptors[dstIx], *structDesc)) {
+ ++dstIx;
+ continue;
+ }
+ res = Status::CORRUPTED;
+ break;
}
}
res = Status::NOT_FOUND;
} else if (item->second) {
- objcpy(&descriptors[dstIx++], *item->second);
+ if (objcpy(&descriptors[dstIx], *item->second)) {
+ ++dstIx;
+ continue;
+ }
+ res = Status::CORRUPTED;
+ break;
} else {
res = Status::NO_MEMORY;
+ break;
}
}
descriptors.resize(dstIx);
@@ -292,29 +298,29 @@
return Status::OMITTED;
}
-void ComponentStore::reportComponentDeath(
- const Component::LocalId& componentLocalId) {
- std::lock_guard<std::mutex> lock(mComponentRosterMutex);
- mComponentRoster.erase(componentLocalId);
+Return<sp<IConfigurable>> ComponentStore::getConfigurable() {
+ return mConfigurable;
}
-std::shared_ptr<C2Component> ComponentStore::findC2Component(
- const sp<IComponent>& component) const {
+// Called from createComponent() after a successful creation of `component`.
+void ComponentStore::reportComponentBirth(Component* component) {
+ ComponentStatus componentStatus;
+ componentStatus.c2Component = component->mComponent;
+ componentStatus.birthTime = std::chrono::system_clock::now();
+
std::lock_guard<std::mutex> lock(mComponentRosterMutex);
- Component::LocalId it = mComponentRoster.find(
- Component::InterfaceKey(component));
- if (it == mComponentRoster.end()) {
- return std::shared_ptr<C2Component>();
- }
- return it->second.lock();
+ mComponentRoster.emplace(component, componentStatus);
}
-// Debug dump
+// Called from within the destructor of `component`. No virtual function calls
+// are made on `component` here.
+void ComponentStore::reportComponentDeath(Component* component) {
+ std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+ mComponentRoster.erase(component);
+}
-namespace /* unnamed */ {
-
-// Dump component traits
-std::ostream& dump(
+// Dumps component traits.
+std::ostream& ComponentStore::dump(
std::ostream& out,
const std::shared_ptr<const C2Component::Traits>& comp) {
@@ -334,25 +340,38 @@
return out;
}
-// Dump component
-std::ostream& dump(
+// Dumps component status.
+std::ostream& ComponentStore::dump(
std::ostream& out,
- const std::shared_ptr<C2Component>& comp) {
+ ComponentStatus& compStatus) {
constexpr const char indent[] = " ";
- std::shared_ptr<C2ComponentInterface> intf = comp->intf();
+ // Print birth time.
+ std::chrono::milliseconds ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ compStatus.birthTime.time_since_epoch());
+ std::time_t birthTime = std::chrono::system_clock::to_time_t(
+ compStatus.birthTime);
+ std::tm tm = *std::localtime(&birthTime);
+ out << indent << "Creation time: "
+ << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
+ << '.' << std::setfill('0') << std::setw(3) << ms.count() % 1000
+ << std::endl;
+
+ // Print name and id.
+ std::shared_ptr<C2ComponentInterface> intf = compStatus.c2Component->intf();
if (!intf) {
- out << indent << "Unknown -- null interface" << std::endl;
+ out << indent << "Unknown component -- null interface" << std::endl;
return out;
}
- out << indent << "name: " << intf->getName() << std::endl;
- out << indent << "id: " << intf->getId() << std::endl;
+ out << indent << "Name: " << intf->getName() << std::endl;
+ out << indent << "Id: " << intf->getId() << std::endl;
+
return out;
}
-} // unnamed namespace
-
+// Dumps information when lshal is called.
Return<void> ComponentStore::debug(
const hidl_handle& handle,
const hidl_vec<hidl_string>& /* args */) {
@@ -387,31 +406,16 @@
}
}
- // Retrieve the list of active components.
- std::list<std::shared_ptr<C2Component>> activeComps;
- {
- std::lock_guard<std::mutex> lock(mComponentRosterMutex);
- auto i = mComponentRoster.begin();
- while (i != mComponentRoster.end()) {
- std::shared_ptr<C2Component> c2comp = i->second.lock();
- if (!c2comp) {
- auto j = i;
- ++i;
- mComponentRoster.erase(j);
- } else {
- ++i;
- activeComps.emplace_back(c2comp);
- }
- }
- }
-
// Dump active components.
- out << indent << "Active components:" << std::endl << std::endl;
- if (activeComps.size() == 0) {
- out << indent << indent << "NONE" << std::endl << std::endl;
- } else {
- for (const std::shared_ptr<C2Component>& c2comp : activeComps) {
- dump(out, c2comp) << std::endl;
+ {
+ out << indent << "Active components:" << std::endl << std::endl;
+ std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+ if (mComponentRoster.size() == 0) {
+ out << indent << indent << "NONE" << std::endl << std::endl;
+ } else {
+ for (auto& pair : mComponentRoster) {
+ dump(out, pair.second) << std::endl;
+ }
}
}
diff --git a/media/codec2/hidl/1.0/utils/Configurable.cpp b/media/codec2/hidl/1.0/utils/Configurable.cpp
index d023ba8..a35b74c 100644
--- a/media/codec2/hidl/1.0/utils/Configurable.cpp
+++ b/media/codec2/hidl/1.0/utils/Configurable.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,11 +16,12 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2-Configurable"
-#include <log/log.h>
+#include <android-base/logging.h>
#include <codec2/hidl/1.0/Configurable.h>
#include <codec2/hidl/1.0/ComponentStore.h>
#include <codec2/hidl/1.0/types.h>
+
#include <C2ParamInternal.h>
namespace android {
@@ -33,8 +34,8 @@
using namespace ::android;
CachedConfigurable::CachedConfigurable(
- std::unique_ptr<ConfigurableC2Intf>&& intf) :
- mIntf(std::move(intf)) {
+ std::unique_ptr<ConfigurableC2Intf>&& intf)
+ : mIntf{std::move(intf)} {
}
c2_status_t CachedConfigurable::init(ComponentStore* store) {
@@ -45,6 +46,10 @@
}
// Methods from ::android::hardware::media::c2::V1_0::IConfigurable follow.
+Return<uint32_t> CachedConfigurable::getId() {
+ return mIntf->getId();
+}
+
Return<void> CachedConfigurable::getName(getName_cb _hidl_cb) {
_hidl_cb(mIntf->getName());
return Void();
@@ -65,9 +70,10 @@
&c2heapParams);
hidl_vec<uint8_t> params;
- createParamsBlob(¶ms, c2heapParams);
+ if (!createParamsBlob(¶ms, c2heapParams)) {
+ LOG(WARNING) << "query -- invalid output params.";
+ }
_hidl_cb(static_cast<Status>(c2res), params);
-
return Void();
}
@@ -78,7 +84,8 @@
// inParams is not writable, so create a copy as config modifies the parameters
hidl_vec<uint8_t> inParamsCopy = inParams;
std::vector<C2Param*> c2params;
- if (parseParamsBlob(&c2params, inParamsCopy) != C2_OK) {
+ if (!parseParamsBlob(&c2params, inParamsCopy)) {
+ LOG(WARNING) << "config -- invalid input params.";
_hidl_cb(Status::CORRUPTED,
hidl_vec<SettingResult>(),
hidl_vec<uint8_t>());
@@ -95,13 +102,20 @@
size_t ix = 0;
for (const std::unique_ptr<C2SettingResult>& c2result : c2failures) {
if (c2result) {
- objcpy(&failures[ix++], *c2result);
+ if (objcpy(&failures[ix], *c2result)) {
+ ++ix;
+ } else {
+ LOG(DEBUG) << "config -- invalid setting results.";
+ break;
+ }
}
}
failures.resize(ix);
}
hidl_vec<uint8_t> outParams;
- createParamsBlob(&outParams, c2params);
+ if (!createParamsBlob(&outParams, c2params)) {
+ LOG(DEBUG) << "config -- invalid output params.";
+ }
_hidl_cb((Status)c2res, failures, outParams);
return Void();
}
@@ -117,7 +131,13 @@
size_t dstIx = 0;
for (size_t srcIx = request.offset(); srcIx < request.endOffset(); ++srcIx) {
if (mSupportedParams[srcIx]) {
- objcpy(¶ms[dstIx++], *mSupportedParams[srcIx]);
+ if (objcpy(¶ms[dstIx], *mSupportedParams[srcIx])) {
+ ++dstIx;
+ } else {
+ res = Status::CORRUPTED;
+ LOG(WARNING) << "querySupportedParams -- invalid output params.";
+ break;
+ }
} else {
res = Status::BAD_INDEX;
}
@@ -154,7 +174,14 @@
{
size_t ix = 0;
for (const C2FieldSupportedValuesQuery &result : c2fields) {
- objcpy(&outFields[ix++], result);
+ if (!objcpy(&outFields[ix], result)) {
+ ++ix;
+ } else {
+ outFields.resize(ix);
+ c2res = C2_CORRUPTED;
+ LOG(WARNING) << "querySupportedValues -- invalid output params.";
+ break;
+ }
}
}
_hidl_cb((Status)c2res, outFields);
diff --git a/media/codec2/hidl/1.0/utils/InputBufferManager.cpp b/media/codec2/hidl/1.0/utils/InputBufferManager.cpp
new file mode 100644
index 0000000..a023a05
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/InputBufferManager.cpp
@@ -0,0 +1,461 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "Codec2-InputBufferManager"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/InputBufferManager.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android-base/logging.h>
+
+#include <C2Buffer.h>
+#include <C2Work.h>
+
+#include <chrono>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+void InputBufferManager::registerFrameData(
+ const sp<IComponentListener>& listener,
+ const C2FrameData& input) {
+ getInstance()._registerFrameData(listener, input);
+}
+
+void InputBufferManager::unregisterFrameData(
+ const wp<IComponentListener>& listener,
+ const C2FrameData& input) {
+ getInstance()._unregisterFrameData(listener, input);
+}
+
+void InputBufferManager::unregisterFrameData(
+ const wp<IComponentListener>& listener) {
+ getInstance()._unregisterFrameData(listener);
+}
+
+void InputBufferManager::setNotificationInterval(
+ nsecs_t notificationIntervalNs) {
+ getInstance()._setNotificationInterval(notificationIntervalNs);
+}
+
+void InputBufferManager::_registerFrameData(
+ const sp<IComponentListener>& listener,
+ const C2FrameData& input) {
+ uint64_t frameIndex = input.ordinal.frameIndex.peeku();
+ LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- called with "
+ << "listener @ 0x" << std::hex << listener.get()
+ << ", frameIndex = " << std::dec << frameIndex
+ << ".";
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ std::set<TrackedBuffer> &bufferIds =
+ mTrackedBuffersMap[listener][frameIndex];
+
+ for (size_t i = 0; i < input.buffers.size(); ++i) {
+ if (!input.buffers[i]) {
+ LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- "
+ << "Input buffer at index " << i << " is null.";
+ continue;
+ }
+ const TrackedBuffer &bufferId =
+ *bufferIds.emplace(listener, frameIndex, i, input.buffers[i]).
+ first;
+
+ c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
+ onBufferDestroyed,
+ const_cast<void*>(reinterpret_cast<const void*>(&bufferId)));
+ if (status != C2_OK) {
+ LOG(DEBUG) << "InputBufferManager::_registerFrameData -- "
+ << "registerOnDestroyNotify() failed "
+ << "(listener @ 0x" << std::hex << listener.get()
+ << ", frameIndex = " << std::dec << frameIndex
+ << ", bufferIndex = " << i
+ << ") => status = " << status
+ << ".";
+ }
+ }
+
+ mDeathNotifications.emplace(
+ listener,
+ DeathNotifications(
+ mNotificationIntervalNs.load(std::memory_order_relaxed)));
+}
+
+// Remove a pair (listener, frameIndex) from mTrackedBuffersMap and
+// mDeathNotifications. This implies all bufferIndices are removed.
+//
+// This is called from onWorkDone() and flush().
+void InputBufferManager::_unregisterFrameData(
+ const wp<IComponentListener>& listener,
+ const C2FrameData& input) {
+ uint64_t frameIndex = input.ordinal.frameIndex.peeku();
+ LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
+ << "listener @ 0x" << std::hex << listener.unsafe_get()
+ << ", frameIndex = " << std::dec << frameIndex
+ << ".";
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ auto findListener = mTrackedBuffersMap.find(listener);
+ if (findListener != mTrackedBuffersMap.end()) {
+ std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
+ = findListener->second;
+ auto findFrameIndex = frameIndex2BufferIds.find(frameIndex);
+ if (findFrameIndex != frameIndex2BufferIds.end()) {
+ std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
+ for (const TrackedBuffer& bufferId : bufferIds) {
+ std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
+ if (buffer) {
+ c2_status_t status = buffer->unregisterOnDestroyNotify(
+ onBufferDestroyed,
+ const_cast<void*>(
+ reinterpret_cast<const void*>(&bufferId)));
+ if (status != C2_OK) {
+ LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
+ << "-- unregisterOnDestroyNotify() failed "
+ << "(listener @ 0x"
+ << std::hex
+ << bufferId.listener.unsafe_get()
+ << ", frameIndex = "
+ << std::dec << bufferId.frameIndex
+ << ", bufferIndex = " << bufferId.bufferIndex
+ << ") => status = " << status
+ << ".";
+ }
+ }
+ }
+
+ frameIndex2BufferIds.erase(findFrameIndex);
+ if (frameIndex2BufferIds.empty()) {
+ mTrackedBuffersMap.erase(findListener);
+ }
+ }
+ }
+
+ auto findListenerD = mDeathNotifications.find(listener);
+ if (findListenerD != mDeathNotifications.end()) {
+ DeathNotifications &deathNotifications = findListenerD->second;
+ auto findFrameIndex = deathNotifications.indices.find(frameIndex);
+ if (findFrameIndex != deathNotifications.indices.end()) {
+ std::vector<size_t> &bufferIndices = findFrameIndex->second;
+ deathNotifications.count -= bufferIndices.size();
+ deathNotifications.indices.erase(findFrameIndex);
+ }
+ }
+}
+
+// Remove listener from mTrackedBuffersMap and mDeathNotifications. This implies
+// all frameIndices and bufferIndices are removed.
+//
+// This is called when the component cleans up all input buffers, i.e., when
+// reset(), release(), stop() or ~Component() is called.
+void InputBufferManager::_unregisterFrameData(
+ const wp<IComponentListener>& listener) {
+ LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
+ << "listener @ 0x" << std::hex << listener.unsafe_get()
+ << std::dec << ".";
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ auto findListener = mTrackedBuffersMap.find(listener);
+ if (findListener != mTrackedBuffersMap.end()) {
+ std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds =
+ findListener->second;
+ for (auto findFrameIndex = frameIndex2BufferIds.begin();
+ findFrameIndex != frameIndex2BufferIds.end();
+ ++findFrameIndex) {
+ std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
+ for (const TrackedBuffer& bufferId : bufferIds) {
+ std::shared_ptr<C2Buffer> buffer = bufferId.buffer.lock();
+ if (buffer) {
+ c2_status_t status = buffer->unregisterOnDestroyNotify(
+ onBufferDestroyed,
+ const_cast<void*>(
+ reinterpret_cast<const void*>(&bufferId)));
+ if (status != C2_OK) {
+ LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
+ << "-- unregisterOnDestroyNotify() failed "
+ << "(listener @ 0x"
+ << std::hex
+ << bufferId.listener.unsafe_get()
+ << ", frameIndex = "
+ << std::dec << bufferId.frameIndex
+ << ", bufferIndex = " << bufferId.bufferIndex
+ << ") => status = " << status
+ << ".";
+ }
+ }
+ }
+ }
+ mTrackedBuffersMap.erase(findListener);
+ }
+
+ mDeathNotifications.erase(listener);
+}
+
+// Set mNotificationIntervalNs.
+void InputBufferManager::_setNotificationInterval(
+ nsecs_t notificationIntervalNs) {
+ mNotificationIntervalNs.store(
+ notificationIntervalNs,
+ std::memory_order_relaxed);
+}
+
+// Move a buffer from mTrackedBuffersMap to mDeathNotifications.
+// This is called when a registered C2Buffer object is destroyed.
+void InputBufferManager::onBufferDestroyed(const C2Buffer* buf, void* arg) {
+ getInstance()._onBufferDestroyed(buf, arg);
+}
+
+void InputBufferManager::_onBufferDestroyed(const C2Buffer* buf, void* arg) {
+ if (!buf || !arg) {
+ LOG(WARNING) << "InputBufferManager::_onBufferDestroyed -- called with "
+ << "null argument (s): "
+ << "buf @ 0x" << std::hex << buf
+ << ", arg @ 0x" << std::hex << arg
+ << std::dec << ".";
+ return;
+ }
+ TrackedBuffer id(*reinterpret_cast<TrackedBuffer*>(arg));
+ LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
+ << "buf @ 0x" << std::hex << buf
+ << ", arg @ 0x" << std::hex << arg
+ << std::dec << " -- "
+ << "listener @ 0x" << std::hex << id.listener.unsafe_get()
+ << ", frameIndex = " << std::dec << id.frameIndex
+ << ", bufferIndex = " << id.bufferIndex
+ << ".";
+
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ auto findListener = mTrackedBuffersMap.find(id.listener);
+ if (findListener == mTrackedBuffersMap.end()) {
+ LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+ << "received invalid listener: "
+ << "listener @ 0x" << std::hex << id.listener.unsafe_get()
+ << " (frameIndex = " << std::dec << id.frameIndex
+ << ", bufferIndex = " << id.bufferIndex
+ << ").";
+ return;
+ }
+
+ std::map<uint64_t, std::set<TrackedBuffer>> &frameIndex2BufferIds
+ = findListener->second;
+ auto findFrameIndex = frameIndex2BufferIds.find(id.frameIndex);
+ if (findFrameIndex == frameIndex2BufferIds.end()) {
+ LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+ << "received invalid frame index: "
+ << "frameIndex = " << id.frameIndex
+ << " (listener @ 0x" << std::hex << id.listener.unsafe_get()
+ << ", bufferIndex = " << std::dec << id.bufferIndex
+ << ").";
+ return;
+ }
+
+ std::set<TrackedBuffer> &bufferIds = findFrameIndex->second;
+ auto findBufferId = bufferIds.find(id);
+ if (findBufferId == bufferIds.end()) {
+ LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+ << "received invalid buffer index: "
+ << "bufferIndex = " << id.bufferIndex
+ << " (frameIndex = " << id.frameIndex
+ << ", listener @ 0x" << std::hex << id.listener.unsafe_get()
+ << std::dec << ").";
+ return;
+ }
+
+ bufferIds.erase(findBufferId);
+ if (bufferIds.empty()) {
+ frameIndex2BufferIds.erase(findFrameIndex);
+ if (frameIndex2BufferIds.empty()) {
+ mTrackedBuffersMap.erase(findListener);
+ }
+ }
+
+ DeathNotifications &deathNotifications = mDeathNotifications[id.listener];
+ deathNotifications.indices[id.frameIndex].emplace_back(id.bufferIndex);
+ ++deathNotifications.count;
+ mOnBufferDestroyed.notify_one();
+}
+
+// Notify the clients about buffer destructions.
+// Return false if all destructions have been notified.
+// Return true and set timeToRetry to the time point to wait for before
+// retrying if some destructions have not been notified.
+bool InputBufferManager::processNotifications(nsecs_t* timeToRetryNs) {
+
+ struct Notification {
+ sp<IComponentListener> listener;
+ hidl_vec<IComponentListener::InputBuffer> inputBuffers;
+ Notification(const sp<IComponentListener>& l, size_t s)
+ : listener(l), inputBuffers(s) {}
+ };
+ std::list<Notification> notifications;
+ nsecs_t notificationIntervalNs =
+ mNotificationIntervalNs.load(std::memory_order_relaxed);
+
+ bool retry = false;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ *timeToRetryNs = notificationIntervalNs;
+ nsecs_t timeNowNs = systemTime();
+ for (auto it = mDeathNotifications.begin();
+ it != mDeathNotifications.end(); ) {
+ sp<IComponentListener> listener = it->first.promote();
+ if (!listener) {
+ ++it;
+ continue;
+ }
+ DeathNotifications &deathNotifications = it->second;
+
+ nsecs_t timeSinceLastNotifiedNs =
+ timeNowNs - deathNotifications.lastSentNs;
+ // If not enough time has passed since the last callback, leave the
+ // notifications for this listener untouched for now and retry
+ // later.
+ if (timeSinceLastNotifiedNs < notificationIntervalNs) {
+ retry = true;
+ *timeToRetryNs = std::min(*timeToRetryNs,
+ notificationIntervalNs - timeSinceLastNotifiedNs);
+ LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+ << "Notifications for listener @ "
+ << std::hex << listener.get()
+ << " will be postponed.";
+ ++it;
+ continue;
+ }
+
+ // If enough time has passed since the last notification to this
+ // listener but there are currently no pending notifications, the
+ // listener can be removed from mDeathNotifications---there is no
+ // need to keep track of the last notification time anymore.
+ if (deathNotifications.count == 0) {
+ it = mDeathNotifications.erase(it);
+ continue;
+ }
+
+ // Create the argument for the callback.
+ notifications.emplace_back(listener, deathNotifications.count);
+ hidl_vec<IComponentListener::InputBuffer> &inputBuffers =
+ notifications.back().inputBuffers;
+ size_t i = 0;
+ for (std::pair<const uint64_t, std::vector<size_t>>& p :
+ deathNotifications.indices) {
+ uint64_t frameIndex = p.first;
+ const std::vector<size_t> &bufferIndices = p.second;
+ for (const size_t& bufferIndex : bufferIndices) {
+ IComponentListener::InputBuffer &inputBuffer
+ = inputBuffers[i++];
+ inputBuffer.arrayIndex = bufferIndex;
+ inputBuffer.frameIndex = frameIndex;
+ }
+ }
+
+ // Clear deathNotifications for this listener and set retry to true
+ // so processNotifications will be called again. This will
+ // guarantee that a listener with no pending notifications will
+ // eventually be removed from mDeathNotifications after
+ // mNotificationIntervalNs nanoseconds has passed.
+ retry = true;
+ deathNotifications.indices.clear();
+ deathNotifications.count = 0;
+ deathNotifications.lastSentNs = timeNowNs;
+ ++it;
+ }
+ }
+
+ // Call onInputBuffersReleased() outside the lock to avoid deadlock.
+ for (const Notification& notification : notifications) {
+ if (!notification.listener->onInputBuffersReleased(
+ notification.inputBuffers).isOk()) {
+ // This may trigger if the client has died.
+ LOG(DEBUG) << "InputBufferManager::processNotifications -- "
+ << "failed to send death notifications to "
+ << "listener @ 0x" << std::hex
+ << notification.listener.get()
+ << std::dec << ".";
+ } else {
+#if LOG_NDEBUG == 0
+ std::stringstream inputBufferLog;
+ for (const IComponentListener::InputBuffer& inputBuffer :
+ notification.inputBuffers) {
+ inputBufferLog << " (" << inputBuffer.frameIndex
+ << ", " << inputBuffer.arrayIndex
+ << ")";
+ }
+ LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+ << "death notifications sent to "
+ << "listener @ 0x" << std::hex
+ << notification.listener.get()
+ << std::dec
+ << " with these (frameIndex, bufferIndex) pairs:"
+ << inputBufferLog.str();
+#endif
+ }
+ }
+#if LOG_NDEBUG == 0
+ if (retry) {
+ LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+ << "will retry again in " << *timeToRetryNs << "ns.";
+ } else {
+ LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+ << "no pending death notifications.";
+ }
+#endif
+ return retry;
+}
+
+void InputBufferManager::main() {
+ LOG(VERBOSE) << "InputBufferManager main -- started.";
+ nsecs_t timeToRetryNs;
+ while (true) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mDeathNotifications.empty()) {
+ mOnBufferDestroyed.wait(lock);
+ }
+ lock.unlock();
+ while (processNotifications(&timeToRetryNs)) {
+ std::this_thread::sleep_for(
+ std::chrono::nanoseconds(timeToRetryNs));
+ }
+ }
+}
+
+InputBufferManager::InputBufferManager()
+ : mMainThread{&InputBufferManager::main, this} {
+}
+
+InputBufferManager& InputBufferManager::getInstance() {
+ static InputBufferManager instance{};
+ return instance;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+
+
diff --git a/media/codec2/hidl/1.0/utils/InputSurface.cpp b/media/codec2/hidl/1.0/utils/InputSurface.cpp
index b669460..2cbe64b 100644
--- a/media/codec2/hidl/1.0/utils/InputSurface.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurface.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,12 +16,11 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2-InputSurface"
-#include <log/log.h>
+#include <android-base/logging.h>
#include <codec2/hidl/1.0/InputSurface.h>
#include <codec2/hidl/1.0/InputSurfaceConnection.h>
-#include <util/C2InterfaceHelper.h>
#include <C2Component.h>
#include <C2Config.h>
@@ -36,9 +35,10 @@
using namespace ::android;
-class InputSurface::ConfigurableImpl : public C2InterfaceHelper {
+// Derived class of C2InterfaceHelper
+class InputSurface::Interface : public C2InterfaceHelper {
public:
- explicit ConfigurableImpl(
+ explicit Interface(
const std::shared_ptr<C2ReflectorHelper> &helper)
: C2InterfaceHelper(helper) {
@@ -63,33 +63,34 @@
std::shared_ptr<C2InputSurfaceEosTuning> mEos;
};
-namespace {
-
-class ConfigurableWrapper : public ConfigurableC2Intf {
+// Derived class of ConfigurableC2Intf
+class InputSurface::ConfigurableIntf : public ConfigurableC2Intf {
public:
- ConfigurableWrapper(
- const std::shared_ptr<InputSurface::ConfigurableImpl> &impl,
+ ConfigurableIntf(
+ const std::shared_ptr<InputSurface::Interface> &intf,
const sp<GraphicBufferSource> &source)
- : ConfigurableC2Intf("input-surface"),
- mImpl(impl),
+ : ConfigurableC2Intf("input-surface", 0),
+ mIntf(intf),
mSource(source) {
}
- ~ConfigurableWrapper() override = default;
+ virtual ~ConfigurableIntf() override = default;
- c2_status_t query(
+ virtual c2_status_t query(
const std::vector<C2Param::Index> &indices,
c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const params) const override {
- return mImpl->query({}, indices, mayBlock, params);
+ std::vector<std::unique_ptr<C2Param>>* const params
+ ) const override {
+ return mIntf->query({}, indices, mayBlock, params);
}
- c2_status_t config(
+ virtual c2_status_t config(
const std::vector<C2Param*> ¶ms,
c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
- c2_status_t err = mImpl->config(params, mayBlock, failures);
- if (mImpl->eos()) {
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures
+ ) override {
+ c2_status_t err = mIntf->config(params, mayBlock, failures);
+ if (mIntf->eos()) {
sp<GraphicBufferSource> source = mSource.promote();
if (source == nullptr || source->signalEndOfInputStream() != OK) {
// TODO: put something in |failures|
@@ -100,202 +101,71 @@
return err;
}
- c2_status_t querySupportedParams(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const override {
- return mImpl->querySupportedParams(params);
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+ ) const override {
+ return mIntf->querySupportedParams(params);
}
- c2_status_t querySupportedValues(
+ virtual c2_status_t querySupportedValues(
std::vector<C2FieldSupportedValuesQuery>& fields,
c2_blocking_t mayBlock) const override {
- return mImpl->querySupportedValues(fields, mayBlock);
+ return mIntf->querySupportedValues(fields, mayBlock);
}
private:
- const std::shared_ptr<InputSurface::ConfigurableImpl> mImpl;
+ const std::shared_ptr<InputSurface::Interface> mIntf;
wp<GraphicBufferSource> mSource;
};
-} // namespace
-
-
-Return<void> InputSurface::connectToComponent(
- const sp<IComponent>& component,
- connectToComponent_cb _hidl_cb) {
- Status status;
- sp<InputSurfaceConnection> conn;
- if (!component) {
- status = Status::BAD_VALUE;
- } else {
- std::shared_ptr<C2Component> comp = mStore->findC2Component(component);
- if (!comp) {
- conn = new InputSurfaceConnection(mSource, component);
- } else {
- conn = new InputSurfaceConnection(mSource, comp);
- }
- if (!conn->init()) {
- conn = nullptr;
- status = Status::BAD_VALUE;
- } else {
- status = Status::OK;
- }
- }
- _hidl_cb(status, conn);
- return Void();
+Return<sp<InputSurface::HGraphicBufferProducer>> InputSurface::getGraphicBufferProducer() {
+ return mProducer;
}
Return<sp<IConfigurable>> InputSurface::getConfigurable() {
return mConfigurable;
}
-// Derived methods from IGraphicBufferProducer
-
-Return<void> InputSurface::requestBuffer(
- int32_t slot,
- requestBuffer_cb _hidl_cb) {
- return mBase->requestBuffer(slot, _hidl_cb);
-}
-
-Return<int32_t> InputSurface::setMaxDequeuedBufferCount(
- int32_t maxDequeuedBuffers) {
- return mBase->setMaxDequeuedBufferCount(maxDequeuedBuffers);
-}
-
-Return<int32_t> InputSurface::setAsyncMode(
- bool async) {
- return mBase->setAsyncMode(async);
-}
-
-Return<void> InputSurface::dequeueBuffer(
- uint32_t width,
- uint32_t height,
- PixelFormat format,
- uint32_t usage,
- bool getFrameTimestamps,
- dequeueBuffer_cb _hidl_cb) {
- return mBase->dequeueBuffer(
- width, height, format, usage, getFrameTimestamps, _hidl_cb);
-}
-
-Return<int32_t> InputSurface::detachBuffer(
- int32_t slot) {
- return mBase->detachBuffer(slot);
-}
-
-Return<void> InputSurface::detachNextBuffer(
- detachNextBuffer_cb _hidl_cb) {
- return mBase->detachNextBuffer(_hidl_cb);
-}
-
-Return<void> InputSurface::attachBuffer(
- const AnwBuffer& buffer,
- attachBuffer_cb _hidl_cb) {
- return mBase->attachBuffer(buffer, _hidl_cb);
-}
-
-Return<void> InputSurface::queueBuffer(
- int32_t slot,
- const QueueBufferInput& input,
- queueBuffer_cb _hidl_cb) {
- return mBase->queueBuffer(slot, input, _hidl_cb);
-}
-
-Return<int32_t> InputSurface::cancelBuffer(
- int32_t slot,
- const hidl_handle& fence) {
- return mBase->cancelBuffer(slot, fence);
-}
-
-Return<void> InputSurface::query(
- int32_t what,
- query_cb _hidl_cb) {
- return mBase->query(what, _hidl_cb);
-}
-
Return<void> InputSurface::connect(
- const sp<HProducerListener>& listener,
- int32_t api,
- bool producerControlledByApp,
+ const sp<IInputSink>& sink,
connect_cb _hidl_cb) {
- return mBase->connect(listener, api, producerControlledByApp, _hidl_cb);
+ Status status;
+ sp<InputSurfaceConnection> connection;
+ if (!sink) {
+ _hidl_cb(Status::BAD_VALUE, nullptr);
+ return Void();
+ }
+ std::shared_ptr<C2Component> comp = Component::findLocalComponent(sink);
+ if (comp) {
+ connection = new InputSurfaceConnection(mSource, comp, mStore);
+ } else {
+ connection = new InputSurfaceConnection(mSource, sink, mStore);
+ }
+ if (!connection->init()) {
+ connection = nullptr;
+ status = Status::BAD_VALUE;
+ } else {
+ status = Status::OK;
+ }
+ _hidl_cb(status, connection);
+ return Void();
}
-Return<int32_t> InputSurface::disconnect(
- int32_t api,
- DisconnectMode mode) {
- return mBase->disconnect(api, mode);
-}
-
-Return<int32_t> InputSurface::setSidebandStream(
- const hidl_handle& stream) {
- return mBase->setSidebandStream(stream);
-}
-
-Return<void> InputSurface::allocateBuffers(
- uint32_t width,
- uint32_t height,
- PixelFormat format,
- uint32_t usage) {
- return mBase->allocateBuffers(width, height, format, usage);
-}
-
-Return<int32_t> InputSurface::allowAllocation(
- bool allow) {
- return mBase->allowAllocation(allow);
-}
-
-Return<int32_t> InputSurface::setGenerationNumber(
- uint32_t generationNumber) {
- return mBase->setGenerationNumber(generationNumber);
-}
-
-Return<void> InputSurface::getConsumerName(
- getConsumerName_cb _hidl_cb) {
- return mBase->getConsumerName(_hidl_cb);
-}
-
-Return<int32_t> InputSurface::setSharedBufferMode(
- bool sharedBufferMode) {
- return mBase->setSharedBufferMode(sharedBufferMode);
-}
-
-Return<int32_t> InputSurface::setAutoRefresh(
- bool autoRefresh) {
- return mBase->setAutoRefresh(autoRefresh);
-}
-
-Return<int32_t> InputSurface::setDequeueTimeout(
- int64_t timeoutNs) {
- return mBase->setDequeueTimeout(timeoutNs);
-}
-
-Return<void> InputSurface::getLastQueuedBuffer(
- getLastQueuedBuffer_cb _hidl_cb) {
- return mBase->getLastQueuedBuffer(_hidl_cb);
-}
-
-Return<void> InputSurface::getFrameTimestamps(
- getFrameTimestamps_cb _hidl_cb) {
- return mBase->getFrameTimestamps(_hidl_cb);
-}
-
-Return<void> InputSurface::getUniqueId(
- getUniqueId_cb _hidl_cb) {
- return mBase->getUniqueId(_hidl_cb);
-}
+// Derived methods from IGraphicBufferProducer
// Constructor is exclusive to ComponentStore.
InputSurface::InputSurface(
const sp<ComponentStore>& store,
const std::shared_ptr<C2ReflectorHelper>& reflector,
- const sp<HGraphicBufferProducer>& base,
- const sp<GraphicBufferSource>& source) :
- mStore(store),
- mBase(base),
- mSource(source),
- mHelper(std::make_shared<ConfigurableImpl>(reflector)),
- mConfigurable(new CachedConfigurable(
- std::make_unique<ConfigurableWrapper>(mHelper, source))) {
+ const sp<HGraphicBufferProducer>& producer,
+ const sp<GraphicBufferSource>& source)
+ : mStore{store},
+ mProducer{producer},
+ mSource{source},
+ mIntf{std::make_shared<Interface>(reflector)},
+ mConfigurable{new CachedConfigurable(
+ std::make_unique<ConfigurableIntf>(
+ mIntf, source))} {
mConfigurable->init(store.get());
}
diff --git a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
index 8b1ece3..1024f50 100644
--- a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,9 +16,10 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2-InputSurfaceConnection"
-#include <log/log.h>
+#include <android-base/logging.h>
#include <codec2/hidl/1.0/InputSurfaceConnection.h>
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
#include <memory>
#include <list>
@@ -65,51 +66,74 @@
} // unnamed namespace
+// Derived class of ComponentWrapper for use with
+// GraphicBufferSource::configure().
+//
struct InputSurfaceConnection::Impl : public ComponentWrapper {
+
Impl(const sp<GraphicBufferSource>& source,
- const std::shared_ptr<C2Component>& comp) :
- mSource(source), mComp(comp), mRemoteComp(),
- mFrameIndex(0) {
- std::shared_ptr<C2ComponentInterface> intf = comp->intf();
- mCompName = intf ? intf->getName() : "";
+ const std::shared_ptr<C2Component>& localComp)
+ : mSource{source}, mLocalComp{localComp}, mSink{}, mFrameIndex{0} {
+ std::shared_ptr<C2ComponentInterface> intf = localComp->intf();
+ mSinkName = intf ? intf->getName() : "";
}
Impl(const sp<GraphicBufferSource>& source,
- const sp<IComponent>& comp) :
- mSource(source), mComp(), mRemoteComp(comp),
- mFrameIndex(0) {
- Return<void> transStatus = comp->getName(
- [this](const hidl_string& name) {
- mCompName = name.c_str();
+ const sp<IInputSink>& sink)
+ : mSource{source}, mLocalComp{}, mSink{sink}, mFrameIndex{0} {
+ Return<sp<IConfigurable>> transResult = sink->getConfigurable();
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "Remote sink is dead.";
+ return;
+ }
+ mSinkConfigurable =
+ static_cast<sp<IConfigurable>>(transResult);
+ if (!mSinkConfigurable) {
+ LOG(ERROR) << "Remote sink is not configurable.";
+ mSinkName = "";
+ return;
+ }
+
+ hidl_string name;
+ Return<void> transStatus = mSinkConfigurable->getName(
+ [&name](const hidl_string& n) {
+ name = n;
});
if (!transStatus.isOk()) {
- ALOGD("getName -- Cannot obtain remote component name.");
+ LOG(ERROR) << "Remote sink's configurable is dead.";
+ mSinkName = "";
+ return;
}
+ mSinkName = name.c_str();
}
- virtual ~Impl() = default;
+ virtual ~Impl() {
+ mSource->stop();
+ mSource->release();
+ }
bool init() {
- sp<GraphicBufferSource> source = mSource.promote();
- if (source == nullptr) {
+ if (mSource == nullptr) {
return false;
}
- status_t err = source->initCheck();
+ status_t err = mSource->initCheck();
if (err != OK) {
- ALOGD("Impl::init -- GBS init failed: %d", err);
+ LOG(WARNING) << "Impl::init -- GraphicBufferSource init failed: "
+ << "status = " << err << ".";
return false;
}
// TODO: read settings properly from the interface
C2VideoSizeStreamTuning::input inputSize;
C2StreamUsageTuning::input usage;
- c2_status_t c2Status = compQuery({ &inputSize, &usage },
+ c2_status_t c2Status = queryFromSink({ &inputSize, &usage },
{},
C2_MAY_BLOCK,
nullptr);
if (c2Status != C2_OK) {
- ALOGD("Impl::init -- cannot query information from "
- "the component interface: %s.", asString(c2Status));
+ LOG(WARNING) << "Impl::init -- cannot query information from "
+ "the component interface: "
+ << "status = " << asString(c2Status) << ".";
return false;
}
@@ -122,26 +146,27 @@
// asGrallocUsage();
uint32_t grallocUsage =
- mCompName.compare(0, 11, "c2.android.") == 0 ?
+ mSinkName.compare(0, 11, "c2.android.") == 0 ?
GRALLOC_USAGE_SW_READ_OFTEN :
GRALLOC_USAGE_HW_VIDEO_ENCODER;
- err = source->configure(
+ err = mSource->configure(
this, dataSpace, kBufferCount,
inputSize.width, inputSize.height,
grallocUsage);
if (err != OK) {
- ALOGD("Impl::init -- GBS configure failed: %d", err);
+ LOG(WARNING) << "Impl::init -- GBS configure failed: "
+ << "status = " << err << ".";
return false;
}
for (int32_t i = 0; i < kBufferCount; ++i) {
- if (!source->onInputBufferAdded(i).isOk()) {
- ALOGD("Impl::init: populating GBS slots failed");
+ if (!mSource->onInputBufferAdded(i).isOk()) {
+ LOG(WARNING) << "Impl::init: failed to populate GBS slots.";
return false;
}
}
- if (!source->start().isOk()) {
- ALOGD("Impl::init -- GBS start failed");
+ if (!mSource->start().isOk()) {
+ LOG(WARNING) << "Impl::init -- GBS failed to start.";
return false;
}
mAllocatorMutex.lock();
@@ -150,7 +175,8 @@
&mAllocator);
mAllocatorMutex.unlock();
if (c2err != OK) {
- ALOGD("Impl::init -- failed to fetch gralloc allocator: %d", c2err);
+ LOG(WARNING) << "Impl::init -- failed to fetch gralloc allocator: "
+ << "status = " << asString(c2err) << ".";
return false;
}
return true;
@@ -162,7 +188,7 @@
const sp<GraphicBuffer>& buffer,
int64_t timestamp,
int fenceFd) override {
- ALOGV("Impl::submitBuffer -- bufferId = %d", bufferId);
+ LOG(VERBOSE) << "Impl::submitBuffer -- bufferId = " << bufferId << ".";
// TODO: Use fd to construct fence
(void)fenceFd;
@@ -190,9 +216,8 @@
// TODO: fence
new Buffer2D(block->share(
C2Rect(block->width(), block->height()), ::C2Fence())),
- [bufferId, src = mSource](C2Buffer* ptr) {
+ [bufferId, source = mSource](C2Buffer* ptr) {
delete ptr;
- sp<GraphicBufferSource> source = src.promote();
if (source != nullptr) {
// TODO: fence
(void)source->onInputBufferEmptied(bufferId, -1);
@@ -204,12 +229,13 @@
std::list<std::unique_ptr<C2Work>> items;
items.push_back(std::move(work));
- err = compQueue(&items);
+ err = queueToSink(&items);
return (err == C2_OK) ? OK : UNKNOWN_ERROR;
}
- virtual status_t submitEos(int32_t /* bufferId */) override {
- ALOGV("Impl::submitEos");
+ virtual status_t submitEos(int32_t bufferId) override {
+ LOG(VERBOSE) << "Impl::submitEos -- bufferId = " << bufferId << ".";
+ (void)bufferId;
std::unique_ptr<C2Work> work(new C2Work);
work->input.flags = (C2FrameData::flags_t)0;
@@ -221,11 +247,11 @@
std::list<std::unique_ptr<C2Work>> items;
items.push_back(std::move(work));
- c2_status_t err = compQueue(&items);
+ c2_status_t err = queueToSink(&items);
return (err == C2_OK) ? OK : UNKNOWN_ERROR;
}
- void dispatchDataSpaceChanged(
+ virtual void dispatchDataSpaceChanged(
int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
// TODO
(void)dataSpace;
@@ -233,36 +259,63 @@
(void)pixelFormat;
}
+ // Configurable interface for InputSurfaceConnection::Impl.
+ //
+ // This class is declared as an inner class so that it will have access to
+ // all Impl's members.
+ struct ConfigurableIntf : public ConfigurableC2Intf {
+ sp<Impl> mConnection;
+ ConfigurableIntf(const sp<Impl>& connection)
+ : ConfigurableC2Intf{"input-surface-connection", 0},
+ mConnection{connection} {}
+ virtual c2_status_t config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>> *const failures
+ ) override;
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>> *const params) const override;
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
+ ) const override;
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery> &fields,
+ c2_blocking_t mayBlock) const override;
+ };
+
private:
- c2_status_t compQuery(
+ c2_status_t queryFromSink(
const std::vector<C2Param*> &stackParams,
const std::vector<C2Param::Index> &heapParamIndices,
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2Param>>* const heapParams) {
- std::shared_ptr<C2Component> comp = mComp.lock();
- if (comp) {
- std::shared_ptr<C2ComponentInterface> intf = comp->intf();
+ if (mLocalComp) {
+ std::shared_ptr<C2ComponentInterface> intf = mLocalComp->intf();
if (intf) {
return intf->query_vb(stackParams,
heapParamIndices,
mayBlock,
heapParams);
} else {
- ALOGD("compQuery -- component does not have an interface.");
+ LOG(ERROR) << "queryFromSink -- "
+ << "component does not have an interface.";
return C2_BAD_STATE;
}
}
- if (!mRemoteComp) {
- ALOGD("compQuery -- component no longer exists.");
- return C2_BAD_STATE;
- }
+
+ CHECK(mSink) << "-- queryFromSink "
+ << "-- connection has no sink.";
+ CHECK(mSinkConfigurable) << "-- queryFromSink "
+ << "-- sink has no configurable.";
hidl_vec<ParamIndex> indices(
stackParams.size() + heapParamIndices.size());
size_t numIndices = 0;
for (C2Param* const& stackParam : stackParams) {
if (!stackParam) {
- ALOGD("compQuery -- null stack param encountered.");
+ LOG(DEBUG) << "queryFromSink -- null stack param encountered.";
continue;
}
indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
@@ -277,22 +330,22 @@
heapParams->reserve(heapParams->size() + numIndices);
}
c2_status_t status;
- Return<void> transStatus = mRemoteComp->query(
+ Return<void> transStatus = mSinkConfigurable->query(
indices,
mayBlock == C2_MAY_BLOCK,
[&status, &numStackIndices, &stackParams, heapParams](
Status s, const Params& p) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK && status != C2_BAD_INDEX) {
- ALOGD("compQuery -- call failed: %s.", asString(status));
+ LOG(DEBUG) << "queryFromSink -- call failed: "
+ << "status = " << asString(status) << ".";
return;
}
std::vector<C2Param*> paramPointers;
- c2_status_t parseStatus = parseParamsBlob(¶mPointers, p);
- if (parseStatus != C2_OK) {
- ALOGD("compQuery -- error while parsing params: %s.",
- asString(parseStatus));
- status = parseStatus;
+ if (!parseParamsBlob(¶mPointers, p)) {
+ LOG(DEBUG) << "queryFromSink -- error while "
+ << "parsing params.";
+ status = C2_CORRUPTED;
return;
}
size_t i = 0;
@@ -302,7 +355,8 @@
if (numStackIndices > 0) {
--numStackIndices;
if (!paramPointer) {
- ALOGD("compQuery -- null stack param.");
+ LOG(DEBUG) << "queryFromSink -- "
+ "null stack param.";
++it;
continue;
}
@@ -313,25 +367,27 @@
CHECK(i < stackParams.size());
if (stackParams[i]->index() !=
paramPointer->index()) {
- ALOGD("compQuery -- param skipped. index = %d",
- static_cast<int>(
- stackParams[i]->index()));
+ LOG(DEBUG) << "queryFromSink -- "
+ "param skipped (index = "
+ << stackParams[i]->index() << ").";
stackParams[i++]->invalidate();
continue;
}
if (!stackParams[i++]->updateFrom(*paramPointer)) {
- ALOGD("compQuery -- param update failed: "
- "index = %d.",
- static_cast<int>(paramPointer->index()));
+ LOG(DEBUG) << "queryFromSink -- "
+ "param update failed (index = "
+ << paramPointer->index() << ").";
}
} else {
if (!paramPointer) {
- ALOGD("compQuery -- null heap param.");
+ LOG(DEBUG) << "queryFromSink -- "
+ "null heap param.";
++it;
continue;
}
if (!heapParams) {
- ALOGD("compQuery -- too many stack params.");
+ LOG(WARNING) << "queryFromSink -- "
+ "too many stack params.";
break;
}
heapParams->emplace_back(C2Param::Copy(*paramPointer));
@@ -340,96 +396,130 @@
}
});
if (!transStatus.isOk()) {
- ALOGD("compQuery -- transaction failed.");
+ LOG(ERROR) << "queryFromSink -- transaction failed.";
return C2_CORRUPTED;
}
return status;
}
- c2_status_t compQueue(std::list<std::unique_ptr<C2Work>>* const items) {
- std::shared_ptr<C2Component> comp = mComp.lock();
- if (comp) {
- return comp->queue_nb(items);
+ c2_status_t queueToSink(std::list<std::unique_ptr<C2Work>>* const items) {
+ if (mLocalComp) {
+ return mLocalComp->queue_nb(items);
}
+ CHECK(mSink) << "-- queueToSink "
+ << "-- connection has no sink.";
+
WorkBundle workBundle;
- Status hidlStatus = objcpy(&workBundle, *items, nullptr);
- if (hidlStatus != Status::OK) {
- ALOGD("compQueue -- bad input.");
+ if (!objcpy(&workBundle, *items, nullptr)) {
+ LOG(ERROR) << "queueToSink -- bad input.";
return C2_CORRUPTED;
}
- Return<Status> transStatus = mRemoteComp->queue(workBundle);
+ Return<Status> transStatus = mSink->queue(workBundle);
if (!transStatus.isOk()) {
- ALOGD("compQueue -- transaction failed.");
+ LOG(ERROR) << "queueToSink -- transaction failed.";
return C2_CORRUPTED;
}
c2_status_t status =
static_cast<c2_status_t>(static_cast<Status>(transStatus));
if (status != C2_OK) {
- ALOGV("compQueue -- call failed: %s.", asString(status));
+ LOG(DEBUG) << "queueToSink -- call failed: "
+ << asString(status);
}
return status;
}
- wp<GraphicBufferSource> mSource;
- std::weak_ptr<C2Component> mComp;
- sp<IComponent> mRemoteComp;
- std::string mCompName;
+ sp<GraphicBufferSource> mSource;
+ std::shared_ptr<C2Component> mLocalComp;
+ sp<IInputSink> mSink;
+ sp<IConfigurable> mSinkConfigurable;
+ std::string mSinkName;
// Needed for ComponentWrapper implementation
std::mutex mAllocatorMutex;
std::shared_ptr<C2Allocator> mAllocator;
std::atomic_uint64_t mFrameIndex;
+
};
InputSurfaceConnection::InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
- const std::shared_ptr<C2Component>& comp) :
- mSource(source),
- mImpl(new Impl(source, comp)) {
+ const std::shared_ptr<C2Component>& comp,
+ const sp<ComponentStore>& store)
+ : mImpl{new Impl(source, comp)},
+ mConfigurable{new CachedConfigurable(
+ std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+ mConfigurable->init(store.get());
}
InputSurfaceConnection::InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
- const sp<IComponent>& comp) :
- mSource(source),
- mImpl(new Impl(source, comp)) {
-}
-
-InputSurfaceConnection::~InputSurfaceConnection() {
- if (mSource) {
- (void)mSource->stop();
- (void)mSource->release();
- mSource.clear();
- }
- mImpl.clear();
-}
-
-bool InputSurfaceConnection::init() {
- mMutex.lock();
- sp<Impl> impl = mImpl;
- mMutex.unlock();
-
- if (!impl) {
- return false;
- }
- return impl->init();
+ const sp<IInputSink>& sink,
+ const sp<ComponentStore>& store)
+ : mImpl{new Impl(source, sink)},
+ mConfigurable{new CachedConfigurable(
+ std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+ mConfigurable->init(store.get());
}
Return<Status> InputSurfaceConnection::disconnect() {
- ALOGV("disconnect");
- mMutex.lock();
- if (mSource) {
- (void)mSource->stop();
- (void)mSource->release();
- mSource.clear();
- }
- mImpl.clear();
- mMutex.unlock();
- ALOGV("disconnected");
+ std::lock_guard<std::mutex> lock(mImplMutex);
+ mImpl = nullptr;
return Status::OK;
}
+InputSurfaceConnection::~InputSurfaceConnection() {
+ mImpl = nullptr;
+}
+
+bool InputSurfaceConnection::init() {
+ std::lock_guard<std::mutex> lock(mImplMutex);
+ return mImpl->init();
+}
+
+Return<sp<IConfigurable>> InputSurfaceConnection::getConfigurable() {
+ return mConfigurable;
+}
+
+// Configurable interface for InputSurfaceConnection::Impl
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
+ // TODO: implement
+ (void)params;
+ (void)mayBlock;
+ (void)failures;
+ return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>> *const params) const {
+ // TODO: implement
+ (void)indices;
+ (void)mayBlock;
+ (void)params;
+ return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+ // TODO: implement
+ (void)params;
+ return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery> &fields,
+ c2_blocking_t mayBlock) const {
+ // TODO: implement
+ (void)fields;
+ (void)mayBlock;
+ return C2_OK;
+}
+
} // namespace utils
} // namespace V1_0
} // namespace c2
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
index 0908226..4ac95c5 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Component.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -17,13 +17,15 @@
#ifndef CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
#define CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
+#include <codec2/hidl/1.0/ComponentInterface.h>
#include <codec2/hidl/1.0/Configurable.h>
#include <codec2/hidl/1.0/types.h>
#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.0/IComponent.h>
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
#include <android/hardware/media/c2/1.0/IComponentListener.h>
#include <android/hardware/media/c2/1.0/IComponentStore.h>
-#include <android/hardware/media/c2/1.0/IComponent.h>
#include <hidl/Status.h>
#include <hwbinder/IBinder.h>
@@ -31,9 +33,9 @@
#include <C2Buffer.h>
#include <C2.h>
-#include <list>
#include <map>
#include <memory>
+#include <mutex>
namespace android {
namespace hardware {
@@ -54,19 +56,8 @@
struct ComponentStore;
-struct ComponentInterface : public Configurable<IComponentInterface> {
- ComponentInterface(
- const std::shared_ptr<C2ComponentInterface>& interface,
- const sp<ComponentStore>& store);
- c2_status_t status() const;
-
-protected:
- c2_status_t mInit;
- std::shared_ptr<C2ComponentInterface> mInterface;
- sp<ComponentStore> mStore;
-};
-
-struct Component : public Configurable<IComponent> {
+struct Component : public IComponent,
+ public std::enable_shared_from_this<Component> {
Component(
const std::shared_ptr<C2Component>&,
const sp<IComponentListener>& listener,
@@ -85,10 +76,14 @@
virtual Return<Status> setOutputSurface(
uint64_t blockPoolId,
const sp<HGraphicBufferProducer>& surface) override;
- virtual Return<Status> connectToOmxInputSurface(
+ virtual Return<void> connectToInputSurface(
+ const sp<IInputSurface>& inputSurface,
+ connectToInputSurface_cb _hidl_cb) override;
+ virtual Return<void> connectToOmxInputSurface(
const sp<HGraphicBufferProducer>& producer,
const sp<::android::hardware::media::omx::V1_0::
- IGraphicBufferSource>& source) override;
+ IGraphicBufferSource>& source,
+ connectToOmxInputSurface_cb _hidl_cb) override;
virtual Return<Status> disconnectFromInputSurface() override;
virtual Return<void> createBlockPool(
uint32_t allocatorId,
@@ -98,63 +93,34 @@
virtual Return<Status> stop() override;
virtual Return<Status> reset() override;
virtual Return<Status> release() override;
+ virtual Return<sp<IComponentInterface>> getInterface() override;
+
+ // Returns a C2Component associated to the given sink if the sink is indeed
+ // a local component. Returns nullptr otherwise.
+ //
+ // This function is used by InputSurface::connect().
+ static std::shared_ptr<C2Component> findLocalComponent(
+ const sp<IInputSink>& sink);
protected:
c2_status_t mInit;
std::shared_ptr<C2Component> mComponent;
- std::shared_ptr<C2ComponentInterface> mInterface;
+ sp<ComponentInterface> mInterface;
sp<IComponentListener> mListener;
sp<ComponentStore> mStore;
::android::hardware::media::c2::V1_0::utils::DefaultBufferPoolSender
mBufferPoolSender;
+ struct Sink;
+ std::mutex mSinkMutex;
+ sp<Sink> mSink;
+
std::mutex mBlockPoolsMutex;
// This map keeps C2BlockPool objects that are created by createBlockPool()
// alive. These C2BlockPool objects can be deleted by calling
// destroyBlockPool(), reset() or release(), or by destroying the component.
std::map<uint64_t, std::shared_ptr<C2BlockPool>> mBlockPools;
- // This struct is a comparable wrapper for IComponent.
- //
- // An IComponent object is either local or remote. If it is local, we can
- // use the underlying pointer as a key. If it is remote, we have to use the
- // underlying pointer of the associated binder object as a key.
- //
- // See interfacesEqual() for more detail.
- struct InterfaceKey {
- // An InterfaceKey is constructed from IComponent.
- InterfaceKey(const sp<IComponent>& component);
- // operator< is defined here to control the default definition of
- // std::less<InterfaceKey>, which will be used in type Roster defined
- // below.
- bool operator<(const InterfaceKey& other) const {
- return isRemote ?
- (other.isRemote ?
- // remote & remote
- std::less<IBinder*>()(
- remote.unsafe_get(),
- other.remote.unsafe_get()) :
- // remote & local
- false) :
- (other.isRemote ?
- // local & remote
- true :
- // local & local
- std::less<IComponent*>()(
- local.unsafe_get(),
- other.local.unsafe_get()));
- }
- private:
- bool isRemote;
- wp<IBinder> remote;
- wp<IComponent> local;
- };
-
- typedef std::map<InterfaceKey, std::weak_ptr<C2Component>> Roster;
- typedef Roster::const_iterator LocalId;
- LocalId mLocalId;
- void setLocalId(const LocalId& localId);
-
void initListener(const sp<Component>& self);
virtual ~Component() override;
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
new file mode 100644
index 0000000..a5d235e
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentInterface.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
+#define CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Buffer.h>
+#include <C2.h>
+
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore;
+
+struct ComponentInterface : public IComponentInterface {
+ ComponentInterface(
+ const std::shared_ptr<C2ComponentInterface>& interface,
+ ComponentStore* store);
+ c2_status_t status() const;
+ virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+protected:
+ std::shared_ptr<C2ComponentInterface> mInterface;
+ sp<CachedConfigurable> mConfigurable;
+ c2_status_t mInit;
+};
+
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index 41e1416..be80c62 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,15 +18,18 @@
#define CODEC2_HIDL_V1_0_UTILS_COMPONENTSTORE_H
#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/ComponentInterface.h>
#include <codec2/hidl/1.0/Configurable.h>
-#include <android/hardware/media/c2/1.0/IComponentStore.h>
+
#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
#include <hidl/Status.h>
#include <C2Component.h>
#include <C2Param.h>
#include <C2.h>
+#include <chrono>
#include <map>
#include <memory>
#include <mutex>
@@ -42,53 +45,61 @@
using ::android::hardware::media::bufferpool::V2_0::IClientManager;
-using ::android::hardware::hidl_array;
using ::android::hardware::hidl_handle;
-using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::sp;
-using ::android::wp;
-struct ComponentStore : public Configurable<IComponentStore> {
+struct ComponentStore : public IComponentStore {
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
virtual ~ComponentStore() = default;
- c2_status_t status() const {
- return mInit;
- }
+ /**
+ * Returns the status of the construction of this object.
+ */
+ c2_status_t status() const;
+ /**
+ * This function is called by CachedConfigurable::init() to validate
+ * supported parameters.
+ */
c2_status_t validateSupportedParams(
const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
- // Methods from ::android::hardware::media::c2::V1_0::IComponentStore
- Return<void> createComponent(
+ // Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
+ virtual Return<void> createComponent(
const hidl_string& name,
const sp<IComponentListener>& listener,
const sp<IClientManager>& pool,
createComponent_cb _hidl_cb) override;
- Return<void> createInterface(
+ virtual Return<void> createInterface(
const hidl_string& name,
createInterface_cb _hidl_cb) override;
- Return<void> listComponents(listComponents_cb _hidl_cb) override;
- Return<sp<IInputSurface>> createInputSurface() override;
- Return<void> getStructDescriptors(
+ virtual Return<void> listComponents(listComponents_cb _hidl_cb) override;
+ virtual Return<void> createInputSurface(
+ createInputSurface_cb _hidl_cb) override;
+ virtual Return<void> getStructDescriptors(
const hidl_vec<uint32_t>& indices,
getStructDescriptors_cb _hidl_cb) override;
- Return<sp<IClientManager>> getPoolClientManager() override;
- Return<Status> copyBuffer(
+ virtual Return<sp<IClientManager>> getPoolClientManager() override;
+ virtual Return<Status> copyBuffer(
const Buffer& src,
const Buffer& dst) override;
+ virtual Return<sp<IConfigurable>> getConfigurable() override;
- // Debug dump
- Return<void> debug(
+ /**
+ * Dumps information when lshal is called.
+ */
+ virtual Return<void> debug(
const hidl_handle& handle,
const hidl_vec<hidl_string>& args) override;
protected:
- // does bookkeeping for an interface that has been loaded
+ sp<CachedConfigurable> mConfigurable;
+
+ // Does bookkeeping for an interface that has been loaded.
void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
c2_status_t mInit;
@@ -100,18 +111,33 @@
std::set<C2String> mLoadedInterfaces;
mutable std::mutex mStructDescriptorsMutex;
- // Component lifetime management
- Component::Roster mComponentRoster;
+ // ComponentStore keeps track of live Components.
+
+ struct ComponentStatus {
+ std::shared_ptr<C2Component> c2Component;
+ std::chrono::system_clock::time_point birthTime;
+ };
+
mutable std::mutex mComponentRosterMutex;
- void reportComponentDeath(const Component::LocalId& componentLocalId);
+ std::map<Component*, ComponentStatus> mComponentRoster;
+
+ // Called whenever Component is created.
+ void reportComponentBirth(Component* component);
+ // Called only from the destructor of Component.
+ void reportComponentDeath(Component* component);
friend Component;
- // C2Component lookup
- std::shared_ptr<C2Component> findC2Component(
- const sp<IComponent>& component) const;
+ // Helper functions for dumping.
- friend struct InputSurface;
+ std::ostream& dump(
+ std::ostream& out,
+ const std::shared_ptr<const C2Component::Traits>& comp);
+
+ std::ostream& dump(
+ std::ostream& out,
+ ComponentStatus& compStatus);
+
};
} // namespace utils
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
index 2e33a6f..8095185 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/Configurable.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -17,15 +17,13 @@
#ifndef CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
#define CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
-#include <codec2/hidl/1.0/ConfigurableC2Intf.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <hidl/Status.h>
#include <C2Component.h>
#include <C2Param.h>
#include <C2.h>
-#include <android/hardware/media/c2/1.0/IConfigurable.h>
-#include <hidl/Status.h>
-
#include <memory>
namespace android {
@@ -35,9 +33,6 @@
namespace V1_0 {
namespace utils {
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_memory;
-using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
@@ -46,12 +41,52 @@
struct ComponentStore;
/**
+ * Codec2 objects of different types may have different querying and configuring
+ * functions, but across the Treble boundary, they share the same HIDL
+ * interface, IConfigurable.
+ *
+ * ConfigurableC2Intf is an abstract class that a Codec2 object can implement to
+ * easily expose an IConfigurable instance. See CachedConfigurable below.
+ */
+struct ConfigurableC2Intf {
+ C2String getName() const { return mName; }
+ uint32_t getId() const { return mId; }
+ /** C2ComponentInterface::query_vb sans stack params */
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const params) const = 0;
+ /** C2ComponentInterface::config_vb */
+ virtual c2_status_t config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+ /** C2ComponentInterface::querySupportedParams_nb */
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const = 0;
+ /** C2ComponentInterface::querySupportedParams_nb */
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields, c2_blocking_t mayBlock) const = 0;
+
+ virtual ~ConfigurableC2Intf() = default;
+
+ ConfigurableC2Intf(const C2String& name, uint32_t id)
+ : mName{name}, mId{id} {}
+
+protected:
+ C2String mName; /* cached component name */
+ uint32_t mId;
+};
+
+/**
* Implementation of the IConfigurable interface that supports caching of
* supported parameters from a supplied ComponentStore.
*
- * This is mainly the same for all of the configurable C2 interfaces though
- * there are slight differences in the blocking behavior. This is handled in the
- * ConfigurableC2Intf implementations.
+ * CachedConfigurable essentially converts a ConfigurableC2Intf into HIDL's
+ * IConfigurable. A Codec2 object generally implements ConfigurableC2Intf and
+ * passes the implementation to the constructor of CachedConfigurable.
+ *
+ * Note that caching happens
*/
struct CachedConfigurable : public IConfigurable {
CachedConfigurable(std::unique_ptr<ConfigurableC2Intf>&& intf);
@@ -60,6 +95,8 @@
// Methods from ::android::hardware::media::c2::V1_0::IConfigurable
+ virtual Return<uint32_t> getId() override;
+
virtual Return<void> getName(getName_cb _hidl_cb) override;
virtual Return<void> query(
@@ -90,63 +127,6 @@
std::vector<std::shared_ptr<C2ParamDescriptor>> mSupportedParams;
};
-/**
- * Template that implements the `IConfigurable` interface for an inherited
- * interface. Classes that implement a child interface `I` of `IConfigurable`
- * can derive from `Configurable<I>`.
- */
-template <typename I>
-struct Configurable : public I {
- Configurable(const sp<CachedConfigurable>& intf): mIntf(intf) {
- }
-
- c2_status_t init(ComponentStore* store) {
- return mIntf->init(store);
- }
-
- // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
-
- using getName_cb = typename I::getName_cb;
- virtual Return<void> getName(getName_cb _hidl_cb) override {
- return mIntf->getName(_hidl_cb);
- }
-
- using query_cb = typename I::query_cb;
- virtual Return<void> query(
- const hidl_vec<uint32_t>& indices,
- bool mayBlock,
- query_cb _hidl_cb) override {
- return mIntf->query(indices, mayBlock, _hidl_cb);
- }
-
- using config_cb = typename I::config_cb;
- virtual Return<void> config(
- const hidl_vec<uint8_t>& inParams,
- bool mayBlock,
- config_cb _hidl_cb) override {
- return mIntf->config(inParams, mayBlock, _hidl_cb);
- }
-
- using querySupportedParams_cb = typename I::querySupportedParams_cb;
- virtual Return<void> querySupportedParams(
- uint32_t start,
- uint32_t count,
- querySupportedParams_cb _hidl_cb) override {
- return mIntf->querySupportedParams(start, count, _hidl_cb);
- }
-
- using querySupportedValues_cb = typename I::querySupportedValues_cb;
- virtual Return<void> querySupportedValues(
- const hidl_vec<FieldSupportedValuesQuery>& inFields,
- bool mayBlock,
- querySupportedValues_cb _hidl_cb) override {
- return mIntf->querySupportedValues(inFields, mayBlock, _hidl_cb);
- }
-
-protected:
- sp<CachedConfigurable> mIntf;
-};
-
} // namespace utils
} // namespace V1_0
} // namespace c2
@@ -155,3 +135,4 @@
} // namespace android
#endif // CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
+
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ConfigurableC2Intf.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ConfigurableC2Intf.h
deleted file mode 100644
index b8801bb..0000000
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/ConfigurableC2Intf.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 CODEC2_HIDL_V1_0_UTILS_CONFIGURABLEC2INTF_H
-#define CODEC2_HIDL_V1_0_UTILS_CONFIGURABLEC2INTF_H
-
-#include <C2Work.h>
-#include <C2Component.h>
-#include <C2Param.h>
-#include <C2.h>
-
-#include <hidl/HidlSupport.h>
-#include <utils/StrongPointer.h>
-#include <vector>
-#include <memory>
-
-namespace android {
-namespace hardware {
-namespace media {
-namespace c2 {
-namespace V1_0 {
-namespace utils {
-
-using ::android::sp;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-
-/**
- * Common Codec 2.0 interface wrapper.
- */
-struct ConfigurableC2Intf {
- C2String getName() const { return mName; }
- /** C2ComponentInterface::query_vb sans stack params */
- virtual c2_status_t query(
- const std::vector<C2Param::Index> &indices,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2Param>>* const params) const = 0;
- /** C2ComponentInterface::config_vb */
- virtual c2_status_t config(
- const std::vector<C2Param*> ¶ms,
- c2_blocking_t mayBlock,
- std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
- /** C2ComponentInterface::querySupportedParams_nb */
- virtual c2_status_t querySupportedParams(
- std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const = 0;
- /** C2ComponentInterface::querySupportedParams_nb */
- virtual c2_status_t querySupportedValues(
- std::vector<C2FieldSupportedValuesQuery>& fields, c2_blocking_t mayBlock) const = 0;
-
- virtual ~ConfigurableC2Intf() = default;
-
- ConfigurableC2Intf(const C2String& name) : mName(name) {}
-
-protected:
- C2String mName; /* cache component name */
-};
-
-} // namespace utils
-} // namespace V1_0
-} // namespace c2
-} // namespace media
-} // namespace hardware
-} // namespace android
-
-#endif // CODEC2_HIDL_V1_0_UTILS_CONFIGURABLEC2INTF_H
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h
new file mode 100644
index 0000000..b6857d5
--- /dev/null
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputBufferManager.h
@@ -0,0 +1,294 @@
+/*
+ * 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+#define CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <utils/Timers.h>
+
+#include <C2Buffer.h>
+#include <C2Work.h>
+
+#include <set>
+#include <map>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+/**
+ * InputBufferManager
+ * ==================
+ *
+ * InputBufferManager presents a way to track and untrack input buffers in this
+ * (codec) process and send a notification to a listener, possibly in a
+ * different process, when a tracked buffer no longer has any references in this
+ * process.
+ *
+ * InputBufferManager holds a collection of records representing tracked buffers
+ * and their callback listeners. Conceptually, one record is a triple (listener,
+ * frameIndex, bufferIndex) where
+ *
+ * - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer.
+ * - listener is of type IComponentListener. Its onInputBuffersReleased()
+ * function will be called after the associated buffer dies. The argument of
+ * onInputBuffersReleased() is a list of InputBuffer objects, each of which
+ * has the following members:
+ *
+ * uint64_t frameIndex
+ * uint32_t arrayIndex
+ *
+ * When a tracked buffer associated to the triple (listener, frameIndex,
+ * bufferIndex) goes out of scope, listener->onInputBuffersReleased() will be
+ * called with an InputBuffer object whose members are set as follows:
+ *
+ * inputBuffer.frameIndex = frameIndex
+ * inputBuffer.arrayIndex = bufferIndex
+ *
+ * IPC Optimization
+ * ----------------
+ *
+ * Since onInputBuffersReleased() is an IPC call, InputBufferManager tries not
+ * to call it too often. Any two calls to the same listener are at least
+ * mNotificationIntervalNs nanoseconds apart, where mNotificationIntervalNs is
+ * configurable via calling setNotificationInterval(). The default value of
+ * mNotificationIntervalNs is kDefaultNotificationInternalNs.
+ *
+ * Public Member Functions
+ * -----------------------
+ *
+ * InputBufferManager is a singleton class. Its only instance is accessible via
+ * the following public functions:
+ *
+ * - registerFrameData(const sp<IComponentListener>& listener,
+ * const C2FrameData& input)
+ *
+ * - unregisterFrameData(const sp<IComponentListener>& listener,
+ * const C2FrameData& input)
+ *
+ * - unregisterFrameData(const sp<IComponentListener>& listener)
+ *
+ * - setNotificationInterval(nsecs_t notificationIntervalNs)
+ *
+ */
+
+struct InputBufferManager {
+
+ /**
+ * The default value for the time interval between 2 subsequent IPCs.
+ */
+ static constexpr nsecs_t kDefaultNotificationIntervalNs = 1000000; /* 1ms */
+
+ /**
+ * Track all buffers in a C2FrameData object.
+ *
+ * input (C2FrameData) has the following two members that are of interest:
+ *
+ * C2WorkOrdinal ordinal
+ * vector<shared_ptr<C2Buffer>> buffers
+ *
+ * Calling registerFrameData(listener, input) will register multiple
+ * triples (listener, frameIndex, bufferIndex) where frameIndex is equal to
+ * input.ordinal.frameIndex and bufferIndex runs through the indices of
+ * input.buffers such that input.buffers[bufferIndex] is not null.
+ *
+ * This should be called from queue().
+ *
+ * \param listener Listener of death notifications.
+ * \param input Input frame data whose input buffers are to be tracked.
+ */
+ static void registerFrameData(
+ const sp<IComponentListener>& listener,
+ const C2FrameData& input);
+
+ /**
+ * Untrack all buffers in a C2FrameData object.
+ *
+ * Calling unregisterFrameData(listener, input) will unregister and remove
+ * pending notifications for all triples (l, fi, bufferIndex) such that
+ * l = listener and fi = input.ordinal.frameIndex.
+ *
+ * This should be called from onWorkDone() and flush().
+ *
+ * \param listener Previously registered listener.
+ * \param input Previously registered frame data.
+ */
+ static void unregisterFrameData(
+ const wp<IComponentListener>& listener,
+ const C2FrameData& input);
+
+ /**
+ * Untrack all buffers associated to a given listener.
+ *
+ * Calling unregisterFrameData(listener) will unregister and remove
+ * pending notifications for all triples (l, frameIndex, bufferIndex) such
+ * that l = listener.
+ *
+ * This should be called when the component cleans up all input buffers,
+ * i.e., when reset(), release(), stop() or ~Component() is called.
+ *
+ * \param listener Previously registered listener.
+ */
+ static void unregisterFrameData(
+ const wp<IComponentListener>& listener);
+
+ /**
+ * Set the notification interval.
+ *
+ * \param notificationIntervalNs New notification interval, in nanoseconds.
+ */
+ static void setNotificationInterval(nsecs_t notificationIntervalNs);
+
+private:
+ void _registerFrameData(
+ const sp<IComponentListener>& listener,
+ const C2FrameData& input);
+ void _unregisterFrameData(
+ const wp<IComponentListener>& listener,
+ const C2FrameData& input);
+ void _unregisterFrameData(
+ const wp<IComponentListener>& listener);
+ void _setNotificationInterval(nsecs_t notificationIntervalNs);
+
+ // The callback function tied to C2Buffer objects.
+ //
+ // Note: This function assumes that sInstance is the only instance of this
+ // class.
+ static void onBufferDestroyed(const C2Buffer* buf, void* arg);
+ void _onBufferDestroyed(const C2Buffer* buf, void* arg);
+
+ // Persistent data to be passed as "arg" in onBufferDestroyed().
+ // This is essentially the triple (listener, frameIndex, bufferIndex) plus a
+ // weak pointer to the C2Buffer object.
+ //
+ // Note that the "key" is bufferIndex according to operator<(). This is
+ // designed to work with TrackedBuffersMap defined below.
+ struct TrackedBuffer {
+ wp<IComponentListener> listener;
+ uint64_t frameIndex;
+ size_t bufferIndex;
+ std::weak_ptr<C2Buffer> buffer;
+ TrackedBuffer(const wp<IComponentListener>& listener,
+ uint64_t frameIndex,
+ size_t bufferIndex,
+ const std::shared_ptr<C2Buffer>& buffer)
+ : listener(listener),
+ frameIndex(frameIndex),
+ bufferIndex(bufferIndex),
+ buffer(buffer) {}
+ TrackedBuffer(const TrackedBuffer&) = default;
+ bool operator<(const TrackedBuffer& other) const {
+ return bufferIndex < other.bufferIndex;
+ }
+ };
+
+ // Map: listener -> frameIndex -> set<TrackedBuffer>.
+ // Essentially, this is used to store triples (listener, frameIndex,
+ // bufferIndex) that's searchable by listener and (listener, frameIndex).
+ // However, the value of the innermost map is TrackedBuffer, which also
+ // contains an extra copy of listener and frameIndex. This is needed
+ // because onBufferDestroyed() needs to know listener and frameIndex too.
+ typedef std::map<wp<IComponentListener>,
+ std::map<uint64_t,
+ std::set<TrackedBuffer>>> TrackedBuffersMap;
+
+ // Storage for pending (unsent) death notifications for one listener.
+ // Each pair in member named "indices" are (frameIndex, bufferIndex) from
+ // the (listener, frameIndex, bufferIndex) triple.
+ struct DeathNotifications {
+
+ // The number of pending notifications for this listener.
+ // count may be 0, in which case the DeathNotifications object will
+ // remain valid for only a small period (specified
+ // nanoseconds).
+ size_t count;
+
+ // The timestamp of the most recent callback on this listener. This is
+ // used to guarantee that callbacks do not occur too frequently, and
+ // also to trigger expiration of a DeathNotifications object that has
+ // count = 0.
+ nsecs_t lastSentNs;
+
+ // Map: frameIndex -> vector of bufferIndices
+ // This is essentially a collection of (framdeIndex, bufferIndex).
+ std::map<uint64_t, std::vector<size_t>> indices;
+
+ DeathNotifications(
+ nsecs_t notificationIntervalNs = kDefaultNotificationIntervalNs)
+ : count(0),
+ lastSentNs(systemTime() - notificationIntervalNs),
+ indices() {}
+ };
+
+ // The minimum time period between IPC calls to notify the client about the
+ // destruction of input buffers.
+ std::atomic<nsecs_t> mNotificationIntervalNs{kDefaultNotificationIntervalNs};
+
+ // Mutex for the management of all input buffers.
+ std::mutex mMutex;
+
+ // Tracked input buffers.
+ TrackedBuffersMap mTrackedBuffersMap;
+
+ // Death notifications to be sent.
+ //
+ // A DeathNotifications object is associated to each listener. An entry in
+ // this map will be removed if its associated DeathNotifications has count =
+ // 0 and lastSentNs < systemTime() - mNotificationIntervalNs.
+ std::map<wp<IComponentListener>, DeathNotifications> mDeathNotifications;
+
+ // Condition variable signaled when an entry is added to mDeathNotifications.
+ std::condition_variable mOnBufferDestroyed;
+
+ // Notify the clients about buffer destructions.
+ // Return false if all destructions have been notified.
+ // Return true and set timeToRetry to the duration to wait for before
+ // retrying if some destructions have not been notified.
+ bool processNotifications(nsecs_t* timeToRetryNs);
+
+ // Main function for the input buffer manager thread.
+ void main();
+
+ // The thread that manages notifications.
+ //
+ // Note: This variable is declared last so its initialization will happen
+ // after all other member variables have been initialized.
+ std::thread mMainThread;
+
+ // Private constructor.
+ InputBufferManager();
+
+ // The only instance of this class.
+ static InputBufferManager& getInstance();
+
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
index cef258e..2682c13 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurface.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -19,21 +19,14 @@
#include <codec2/hidl/1.0/ComponentStore.h>
-#include <android/hardware/media/c2/1.0/IInputSurface.h>
-#include <android/hardware/media/c2/1.0/IComponent.h>
-
#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
-#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
-#include <android/hardware/graphics/common/1.0/types.h>
-#include <android/hardware/media/1.0/types.h>
-
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <android/hardware/media/c2/1.0/IInputSurface.h>
#include <gui/IGraphicBufferProducer.h>
+#include <hidl/Status.h>
#include <media/stagefright/bqhelper/GraphicBufferSource.h>
-#include <hidl/HidlSupport.h>
-#include <hidl/Status.h>
-
-class C2ReflectorHelper;
+#include <util/C2InterfaceHelper.h>
namespace android {
namespace hardware {
@@ -49,133 +42,31 @@
using ::android::hardware::Void;
using ::android::sp;
-using ::android::hardware::graphics::common::V1_0::PixelFormat;
-using ::android::hardware::media::V1_0::AnwBuffer;
-
struct InputSurface : public IInputSurface {
- typedef ::android::hidl::base::V1_0::IBase IBase;
-
- typedef ::android::hardware::graphics::bufferqueue::V1_0::
- IProducerListener HProducerListener;
-
- typedef ::android::
- IGraphicBufferProducer BGraphicBufferProducer;
-
typedef ::android::hardware::graphics::bufferqueue::V1_0::
IGraphicBufferProducer HGraphicBufferProducer;
typedef ::android::
GraphicBufferSource GraphicBufferSource;
-// Type disambiguation
-
- typedef ::android::hardware::media::c2::V1_0::Status Status;
-
-// New methods from IInputSurface
-
- virtual Return<void> connectToComponent(
- const sp<IComponent>& component,
- connectToComponent_cb _hidl_cb) override;
+ virtual Return<sp<HGraphicBufferProducer>> getGraphicBufferProducer() override;
virtual Return<sp<IConfigurable>> getConfigurable() override;
-// Methods derived from IGraphicBufferProducer
-
- virtual Return<void> requestBuffer(
- int32_t slot,
- requestBuffer_cb _hidl_cb) override;
-
- virtual Return<int32_t> setMaxDequeuedBufferCount(
- int32_t maxDequeuedBuffers) override;
-
- virtual Return<int32_t> setAsyncMode(
- bool async) override;
-
- virtual Return<void> dequeueBuffer(
- uint32_t width,
- uint32_t height,
- PixelFormat format,
- uint32_t usage,
- bool getFrameTimestamps,
- dequeueBuffer_cb _hidl_cb) override;
-
- virtual Return<int32_t> detachBuffer(
- int32_t slot) override;
-
- virtual Return<void> detachNextBuffer(
- detachNextBuffer_cb _hidl_cb) override;
-
- virtual Return<void> attachBuffer(
- const AnwBuffer& buffer,
- attachBuffer_cb _hidl_cb) override;
-
- virtual Return<void> queueBuffer(
- int32_t slot,
- const QueueBufferInput& input,
- queueBuffer_cb _hidl_cb) override;
-
- virtual Return<int32_t> cancelBuffer(
- int32_t slot,
- const hidl_handle& fence) override;
-
- virtual Return<void> query(
- int32_t what,
- query_cb _hidl_cb) override;
-
virtual Return<void> connect(
- const sp<HProducerListener>& listener,
- int32_t api,
- bool producerControlledByApp,
+ const sp<IInputSink>& sink,
connect_cb _hidl_cb) override;
- virtual Return<int32_t> disconnect(
- int32_t api,
- DisconnectMode mode) override;
-
- virtual Return<int32_t> setSidebandStream(
- const hidl_handle& stream) override;
-
- virtual Return<void> allocateBuffers(
- uint32_t width,
- uint32_t height,
- PixelFormat format,
- uint32_t usage) override;
-
- virtual Return<int32_t> allowAllocation(
- bool allow) override;
-
- virtual Return<int32_t> setGenerationNumber(
- uint32_t generationNumber) override;
-
- virtual Return<void> getConsumerName(
- getConsumerName_cb _hidl_cb) override;
-
- virtual Return<int32_t> setSharedBufferMode(
- bool sharedBufferMode) override;
-
- virtual Return<int32_t> setAutoRefresh(
- bool autoRefresh) override;
-
- virtual Return<int32_t> setDequeueTimeout(
- int64_t timeoutNs) override;
-
- virtual Return<void> getLastQueuedBuffer(
- getLastQueuedBuffer_cb _hidl_cb) override;
-
- virtual Return<void> getFrameTimestamps(
- getFrameTimestamps_cb _hidl_cb) override;
-
- virtual Return<void> getUniqueId(
- getUniqueId_cb _hidl_cb) override;
-
- class ConfigurableImpl;
-
protected:
+
+ class Interface;
+ class ConfigurableIntf;
+
sp<ComponentStore> mStore;
- sp<HGraphicBufferProducer> mBase;
+ sp<HGraphicBufferProducer> mProducer;
sp<GraphicBufferSource> mSource;
- std::shared_ptr<ConfigurableImpl> mHelper;
+ std::shared_ptr<Interface> mIntf;
sp<CachedConfigurable> mConfigurable;
InputSurface(
@@ -187,6 +78,7 @@
virtual ~InputSurface() override = default;
friend struct ComponentStore;
+
};
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
index 904fa9e..758b6b2 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/InputSurfaceConnection.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -18,8 +18,10 @@
#define CODEC2_HIDL_V1_0_UTILS_INPUTSURFACECONNECTION_H
#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/Configurable.h>
#include <android/hardware/media/c2/1.0/IComponent.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
#include <android/hardware/media/c2/1.0/IInputSurfaceConnection.h>
#include <media/stagefright/bqhelper/GraphicBufferSource.h>
@@ -44,19 +46,28 @@
using ::android::sp;
using ::android::GraphicBufferSource;
+// An InputSurfaceConnection connects an InputSurface to a sink, which may be an
+// IInputSink or a local C2Component. This can be specified by choosing the
+// corresponding constructor. The reason for distinguishing these two cases is
+// that when an InputSurfaceConnection lives in the same process as the
+// component that processes the buffers, data parceling is not needed.
struct InputSurfaceConnection : public IInputSurfaceConnection {
virtual Return<Status> disconnect() override;
+ virtual Return<sp<IConfigurable>> getConfigurable() override;
+
protected:
InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
- const std::shared_ptr<C2Component>& component);
+ const std::shared_ptr<C2Component>& comp,
+ const sp<ComponentStore>& store);
InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
- const sp<IComponent>& component);
+ const sp<IInputSink>& sink,
+ const sp<ComponentStore>& store);
bool init();
@@ -68,9 +79,9 @@
struct Impl;
- std::mutex mMutex;
- sp<GraphicBufferSource> mSource;
+ std::mutex mImplMutex;
sp<Impl> mImpl;
+ sp<CachedConfigurable> mConfigurable;
virtual ~InputSurfaceConnection() override;
};
diff --git a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
index d8a50b6..c38e674 100644
--- a/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
+++ b/media/codec2/hidl/1.0/utils/include/codec2/hidl/1.0/types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -17,8 +17,6 @@
#ifndef CODEC2_HIDL_V1_0_UTILS_TYPES_H
#define CODEC2_HIDL_V1_0_UTILS_TYPES_H
-#include <chrono>
-
#include <bufferpool/ClientManager.h>
#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
#include <android/hardware/media/bufferpool/2.0/types.h>
@@ -30,6 +28,9 @@
#include <C2Param.h>
#include <C2ParamDef.h>
#include <C2Work.h>
+#include <util/C2Debug-base.h>
+
+#include <chrono>
using namespace std::chrono_literals;
@@ -65,66 +66,74 @@
};
typedef C2GlobalParam<C2Info, C2Hidl_Rect, 1> C2Hidl_RectInfo;
+// Make asString() and operator<< work with Status as well as c2_status_t.
+C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(Status);
+
+/**
+ * All objcpy() functions will return a boolean value indicating whether the
+ * conversion succeeds or not.
+ */
+
// C2SettingResult -> SettingResult
-Status objcpy(
+bool objcpy(
SettingResult* d,
const C2SettingResult& s);
// SettingResult -> std::unique_ptr<C2SettingResult>
-c2_status_t objcpy(
+bool objcpy(
std::unique_ptr<C2SettingResult>* d,
const SettingResult& s);
// C2ParamDescriptor -> ParamDescriptor
-Status objcpy(
+bool objcpy(
ParamDescriptor* d,
const C2ParamDescriptor& s);
// ParamDescriptor -> std::shared_ptr<C2ParamDescriptor>
-c2_status_t objcpy(
+bool objcpy(
std::shared_ptr<C2ParamDescriptor>* d,
const ParamDescriptor& s);
// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-Status objcpy(
+bool objcpy(
FieldSupportedValuesQuery* d,
const C2FieldSupportedValuesQuery& s);
// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
C2FieldSupportedValuesQuery* d,
const FieldSupportedValuesQuery& s);
// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-Status objcpy(
+bool objcpy(
FieldSupportedValuesQueryResult* d,
const C2FieldSupportedValuesQuery& s);
// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
C2FieldSupportedValuesQuery* d,
const FieldSupportedValuesQuery& sq,
const FieldSupportedValuesQueryResult& sr);
// C2Component::Traits -> ComponentTraits
-Status objcpy(
+bool objcpy(
IComponentStore::ComponentTraits* d,
const C2Component::Traits& s);
// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
// Note: The output d is only valid as long as aliasesBuffer remains alive.
-c2_status_t objcpy(
+bool objcpy(
C2Component::Traits* d,
std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
const IComponentStore::ComponentTraits& s);
// C2StructDescriptor -> StructDescriptor
-Status objcpy(
+bool objcpy(
StructDescriptor* d,
const C2StructDescriptor& s);
// StructDescriptor -> C2StructDescriptor
-c2_status_t objcpy(
+bool objcpy(
std::unique_ptr<C2StructDescriptor>* d,
const StructDescriptor& s);
@@ -208,68 +217,77 @@
// std::list<std::unique_ptr<C2Work>> -> WorkBundle
// Note: If bufferpool will be used, bpSender must not be null.
-Status objcpy(
+bool objcpy(
WorkBundle* d,
const std::list<std::unique_ptr<C2Work>>& s,
BufferPoolSender* bpSender = nullptr);
// WorkBundle -> std::list<std::unique_ptr<C2Work>>
-c2_status_t objcpy(
+bool objcpy(
std::list<std::unique_ptr<C2Work>>* d,
const WorkBundle& s);
/**
- * Parses a params blob and returns C2Param pointers to its params.
+ * Parses a params blob and returns C2Param pointers to its params. The pointers
+ * point to locations inside the underlying buffer of \p blob. If \p blob is
+ * destroyed, the pointers become invalid.
+ *
* \param[out] params target vector of C2Param pointers
* \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed
- * \retval C2_BAD_VALUE otherwise
+ * \retval true if the full blob was parsed
+ * \retval false otherwise
*/
-c2_status_t parseParamsBlob(
+bool parseParamsBlob(
std::vector<C2Param*> *params,
const hidl_vec<uint8_t> &blob);
/**
* Concatenates a list of C2Params into a params blob.
+ *
* \param[out] blob target blob
* \param[in] params parameters to concatenate
- * \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
- * not const)
+ * \retval true if the blob was successfully created
+ * \retval false if the blob was not successful (this only happens if the
+ * parameters were not const)
*/
-Status createParamsBlob(
+bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<C2Param*> ¶ms);
-Status createParamsBlob(
+bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<std::unique_ptr<C2Param>> ¶ms);
-Status createParamsBlob(
+bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<std::shared_ptr<const C2Info>> ¶ms);
-Status createParamsBlob(
+bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<std::unique_ptr<C2Tuning>> ¶ms);
/**
* Parses a params blob and create a vector of C2Params whose members are copies
* of the params in the blob.
+ *
* \param[out] params the resulting vector
* \param[in] blob parameter blob to parse
- * \retval C2_OK if the full blob was parsed and params was constructed
- * \retval C2_BAD_VALUE otherwise
+ * \retval true if the full blob was parsed and params was constructed
+ * \retval false otherwise
*/
-c2_status_t copyParamsFromBlob(
+bool copyParamsFromBlob(
std::vector<std::unique_ptr<C2Param>>* params,
Params blob);
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Tuning>>* params,
+ Params blob);
/**
- * Parses a params blob and applies updates to params
+ * Parses a params blob and applies updates to params.
+ *
* \param[in,out] params params to be updated
* \param[in] blob parameter blob containing updates
- * \retval C2_OK if the full blob was parsed and params was updated
- * \retval C2_BAD_VALUE otherwise
+ * \retval true if the full blob was parsed and params was updated
+ * \retval false otherwise
*/
-c2_status_t updateParamsFromBlob(
+bool updateParamsFromBlob(
const std::vector<C2Param*>& params,
const Params& blob);
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index a128a9d..caed839 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,11 +16,12 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2-types"
-#include <log/log.h>
+#include <android-base/logging.h>
#include <codec2/hidl/1.0/types.h>
#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
+#include <media/stagefright/foundation/AUtils.h>
#include <C2AllocatorIon.h>
#include <C2AllocatorGralloc.h>
@@ -35,10 +36,9 @@
#include <algorithm>
#include <functional>
+#include <iomanip>
#include <unordered_map>
-#include <media/stagefright/foundation/AUtils.h>
-
namespace android {
namespace hardware {
namespace media {
@@ -57,8 +57,18 @@
TransactionId;
using ::android::TWGraphicBufferProducer;
+const char* asString(Status status, const char* def) {
+ return asString(static_cast<c2_status_t>(status), def);
+}
+
namespace /* unnamed */ {
+template <typename EnumClass>
+typename std::underlying_type<EnumClass>::type underlying_value(
+ EnumClass x) {
+ return static_cast<typename std::underlying_type<EnumClass>::type>(x);
+}
+
template <typename Common, typename DstVector, typename SrcVector>
void copyVector(DstVector* d, const SrcVector& s) {
static_assert(sizeof(Common) == sizeof(decltype((*d)[0])),
@@ -73,10 +83,11 @@
}
// C2ParamField -> ParamField
-void objcpy(ParamField *d, const C2ParamField &s) {
+bool objcpy(ParamField *d, const C2ParamField &s) {
d->index = static_cast<ParamIndex>(_C2ParamInspector::GetIndex(s));
d->fieldId.offset = static_cast<uint32_t>(_C2ParamInspector::GetOffset(s));
d->fieldId.size = static_cast<uint32_t>(_C2ParamInspector::GetSize(s));
+ return true;
}
struct C2ParamFieldBuilder : public C2ParamField {
@@ -92,21 +103,23 @@
};
// C2WorkOrdinalStruct -> WorkOrdinal
-void objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
+bool objcpy(WorkOrdinal *d, const C2WorkOrdinalStruct &s) {
d->frameIndex = static_cast<uint64_t>(s.frameIndex.peeku());
d->timestampUs = static_cast<uint64_t>(s.timestamp.peeku());
d->customOrdinal = static_cast<uint64_t>(s.customOrdinal.peeku());
+ return true;
}
// WorkOrdinal -> C2WorkOrdinalStruct
-void objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
+bool objcpy(C2WorkOrdinalStruct *d, const WorkOrdinal &s) {
d->frameIndex = c2_cntr64_t(s.frameIndex);
d->timestamp = c2_cntr64_t(s.timestampUs);
d->customOrdinal = c2_cntr64_t(s.customOrdinal);
+ return true;
}
// C2FieldSupportedValues::range's type -> FieldSupportedValues::Range
-void objcpy(
+bool objcpy(
FieldSupportedValues::Range* d,
const decltype(C2FieldSupportedValues::range)& s) {
d->min = static_cast<PrimitiveValue>(s.min.u64);
@@ -114,21 +127,24 @@
d->step = static_cast<PrimitiveValue>(s.step.u64);
d->num = static_cast<PrimitiveValue>(s.num.u64);
d->denom = static_cast<PrimitiveValue>(s.denom.u64);
+ return true;
}
// C2FieldSupportedValues -> FieldSupportedValues
-Status objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
- d->typeOther = static_cast<int32_t>(s.type);
+bool objcpy(FieldSupportedValues *d, const C2FieldSupportedValues &s) {
switch (s.type) {
case C2FieldSupportedValues::EMPTY:
d->type = FieldSupportedValues::Type::EMPTY;
d->values.resize(0);
- return Status::OK;
+ break;
case C2FieldSupportedValues::RANGE:
d->type = FieldSupportedValues::Type::RANGE;
- objcpy(&d->range, s.range);
+ if (!objcpy(&d->range, s.range)) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+ return false;
+ }
d->values.resize(0);
- return Status::OK;
+ break;
default:
switch (s.type) {
case C2FieldSupportedValues::VALUES:
@@ -138,18 +154,22 @@
d->type = FieldSupportedValues::Type::FLAGS;
break;
default:
- d->type = FieldSupportedValues::Type::OTHER;
- // Copy all fields in this case
- objcpy(&d->range, s.range);
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValues::type_t "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ d->type = static_cast<FieldSupportedValues::Type>(s.type);
+ if (!objcpy(&d->range, s.range)) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValues::range.";
+ return false;
+ }
}
- d->values.resize(s.values.size());
copyVector<uint64_t>(&d->values, s.values);
- return Status::OK;
}
+ return true;
}
// FieldSupportedValues::Range -> C2FieldSupportedValues::range's type
-void objcpy(
+bool objcpy(
decltype(C2FieldSupportedValues::range)* d,
const FieldSupportedValues::Range& s) {
d->min.u64 = static_cast<uint64_t>(s.min);
@@ -157,19 +177,23 @@
d->step.u64 = static_cast<uint64_t>(s.step);
d->num.u64 = static_cast<uint64_t>(s.num);
d->denom.u64 = static_cast<uint64_t>(s.denom);
+ return true;
}
// FieldSupportedValues -> C2FieldSupportedValues
-c2_status_t objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
+bool objcpy(C2FieldSupportedValues *d, const FieldSupportedValues &s) {
switch (s.type) {
case FieldSupportedValues::Type::EMPTY:
d->type = C2FieldSupportedValues::EMPTY;
- return C2_OK;
+ break;
case FieldSupportedValues::Type::RANGE:
d->type = C2FieldSupportedValues::RANGE;
- objcpy(&d->range, s.range);
+ if (!objcpy(&d->range, s.range)) {
+ LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+ return false;
+ }
d->values.resize(0);
- return C2_OK;
+ break;
default:
switch (s.type) {
case FieldSupportedValues::Type::VALUES:
@@ -179,22 +203,30 @@
d->type = C2FieldSupportedValues::FLAGS;
break;
default:
- d->type = static_cast<C2FieldSupportedValues::type_t>(s.typeOther);
- // Copy all fields in this case
- objcpy(&d->range, s.range);
+ LOG(DEBUG) << "Unrecognized FieldSupportedValues::Type "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ d->type = static_cast<C2FieldSupportedValues::type_t>(s.type);
+ if (!objcpy(&d->range, s.range)) {
+ LOG(ERROR) << "Invalid FieldSupportedValues::range.";
+ return false;
+ }
}
copyVector<uint64_t>(&d->values, s.values);
- return C2_OK;
}
+ return true;
}
} // unnamed namespace
// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
-Status objcpy(
+bool objcpy(
FieldSupportedValuesQuery* d,
const C2FieldSupportedValuesQuery& s) {
- objcpy(&d->field, s.field());
+ if (!objcpy(&d->field, s.field())) {
+ LOG(ERROR) << "Invalid C2FieldSupportedValuesQuery::field.";
+ return false;
+ }
switch (s.type()) {
case C2FieldSupportedValuesQuery::POSSIBLE:
d->type = FieldSupportedValuesQuery::Type::POSSIBLE;
@@ -203,15 +235,16 @@
d->type = FieldSupportedValuesQuery::Type::CURRENT;
break;
default:
- ALOGE("Unknown type of C2FieldSupportedValuesQuery: %u",
- static_cast<unsigned>(s.type()));
- return Status::BAD_VALUE;
+ LOG(DEBUG) << "Unrecognized C2FieldSupportedValuesQuery::type_t "
+ << "with underlying value " << underlying_value(s.type())
+ << ".";
+ d->type = static_cast<FieldSupportedValuesQuery::Type>(s.type());
}
- return Status::OK;
+ return true;
}
// FieldSupportedValuesQuery -> C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
C2FieldSupportedValuesQuery* d,
const FieldSupportedValuesQuery& s) {
C2FieldSupportedValuesQuery::type_t dType;
@@ -223,16 +256,17 @@
dType = C2FieldSupportedValuesQuery::CURRENT;
break;
default:
- ALOGE("Unknown type of FieldSupportedValuesQuery: %u",
- static_cast<unsigned>(s.type));
- return C2_BAD_VALUE;
+ LOG(DEBUG) << "Unrecognized FieldSupportedValuesQuery::Type "
+ << "with underlying value " << underlying_value(s.type)
+ << ".";
+ dType = static_cast<C2FieldSupportedValuesQuery::type_t>(s.type);
}
*d = C2FieldSupportedValuesQuery(C2ParamFieldBuilder(s.field), dType);
- return C2_OK;
+ return true;
}
// C2FieldSupportedValuesQuery -> FieldSupportedValuesQueryResult
-Status objcpy(
+bool objcpy(
FieldSupportedValuesQueryResult* d,
const C2FieldSupportedValuesQuery& s) {
d->status = static_cast<Status>(s.status);
@@ -241,20 +275,24 @@
// FieldSupportedValuesQuery, FieldSupportedValuesQueryResult ->
// C2FieldSupportedValuesQuery
-c2_status_t objcpy(
+bool objcpy(
C2FieldSupportedValuesQuery* d,
const FieldSupportedValuesQuery& sq,
const FieldSupportedValuesQueryResult& sr) {
- c2_status_t status = objcpy(d, sq);
- if (status != C2_OK) {
- return status;
+ if (!objcpy(d, sq)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQuery.";
+ return false;
}
d->status = static_cast<c2_status_t>(sr.status);
- return objcpy(&d->values, sr.values);
+ if (!objcpy(&d->values, sr.values)) {
+ LOG(ERROR) << "Invalid FieldSupportedValuesQueryResult::values.";
+ return false;
+ }
+ return true;
}
// C2Component::Traits -> IComponentStore::ComponentTraits
-Status objcpy(
+bool objcpy(
IComponentStore::ComponentTraits *d,
const C2Component::Traits &s) {
d->name = s.name;
@@ -266,10 +304,19 @@
case C2Component::DOMAIN_AUDIO:
d->domain = IComponentStore::ComponentTraits::Domain::AUDIO;
break;
- default:
+ case C2Component::DOMAIN_IMAGE:
+ d->domain = IComponentStore::ComponentTraits::Domain::IMAGE;
+ break;
+ case C2Component::DOMAIN_OTHER:
d->domain = IComponentStore::ComponentTraits::Domain::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::domain_t "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<IComponentStore::ComponentTraits::Domain>(
+ s.domain);
}
- d->domainOther = static_cast<uint32_t>(s.domain);
switch (s.kind) {
case C2Component::KIND_DECODER:
@@ -278,10 +325,16 @@
case C2Component::KIND_ENCODER:
d->kind = IComponentStore::ComponentTraits::Kind::ENCODER;
break;
- default:
+ case C2Component::KIND_OTHER:
d->kind = IComponentStore::ComponentTraits::Kind::OTHER;
+ break;
+ default:
+ LOG(DEBUG) << "Unrecognized C2Component::kind_t "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<IComponentStore::ComponentTraits::Kind>(
+ s.kind);
}
- d->kindOther = static_cast<uint32_t>(s.kind);
d->rank = static_cast<uint32_t>(s.rank);
@@ -292,11 +345,11 @@
--ix;
d->aliases[ix] = s.aliases[ix];
}
- return Status::OK;
+ return true;
}
// ComponentTraits -> C2Component::Traits, std::unique_ptr<std::vector<std::string>>
-c2_status_t objcpy(
+bool objcpy(
C2Component::Traits* d,
std::unique_ptr<std::vector<std::string>>* aliasesBuffer,
const IComponentStore::ComponentTraits& s) {
@@ -309,8 +362,17 @@
case IComponentStore::ComponentTraits::Domain::AUDIO:
d->domain = C2Component::DOMAIN_AUDIO;
break;
+ case IComponentStore::ComponentTraits::Domain::IMAGE:
+ d->domain = C2Component::DOMAIN_IMAGE;
+ break;
+ case IComponentStore::ComponentTraits::Domain::OTHER:
+ d->domain = C2Component::DOMAIN_OTHER;
+ break;
default:
- d->domain = static_cast<C2Component::domain_t>(s.domainOther);
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Domain "
+ << "with underlying value " << underlying_value(s.domain)
+ << ".";
+ d->domain = static_cast<C2Component::domain_t>(s.domain);
}
switch (s.kind) {
@@ -320,8 +382,14 @@
case IComponentStore::ComponentTraits::Kind::ENCODER:
d->kind = C2Component::KIND_ENCODER;
break;
+ case IComponentStore::ComponentTraits::Kind::OTHER:
+ d->kind = C2Component::KIND_OTHER;
+ break;
default:
- d->kind = static_cast<C2Component::kind_t>(s.kindOther);
+ LOG(DEBUG) << "Unrecognized ComponentTraits::Kind "
+ << "with underlying value " << underlying_value(s.kind)
+ << ".";
+ d->kind = static_cast<C2Component::kind_t>(s.kind);
}
d->rank = static_cast<C2Component::rank_t>(s.rank);
@@ -336,52 +404,55 @@
(**aliasesBuffer)[i] = s.aliases[i].c_str();
d->aliases[i] = (**aliasesBuffer)[i].c_str();
}
- return C2_OK;
+ return true;
}
namespace /* unnamed */ {
// C2ParamFieldValues -> ParamFieldValues
-Status objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
- objcpy(&d->paramOrField, s.paramOrField);
+bool objcpy(ParamFieldValues *d, const C2ParamFieldValues &s) {
+ if (!objcpy(&d->paramOrField, s.paramOrField)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::paramOrField.";
+ return false;
+ }
if (s.values) {
d->values.resize(1);
- return objcpy(&d->values[0], *s.values);
+ if (!objcpy(&d->values[0], *s.values)) {
+ LOG(ERROR) << "Invalid C2ParamFieldValues::values.";
+ return false;
+ }
+ return true;
}
d->values.resize(0);
- return Status::OK;
+ return true;
}
// ParamFieldValues -> C2ParamFieldValues
-c2_status_t objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
+bool objcpy(C2ParamFieldValues *d, const ParamFieldValues &s) {
d->paramOrField = C2ParamFieldBuilder(s.paramOrField);
if (s.values.size() == 1) {
d->values = std::make_unique<C2FieldSupportedValues>();
- return objcpy(d->values.get(), s.values[0]);
+ if (!objcpy(d->values.get(), s.values[0])) {
+ LOG(ERROR) << "Invalid ParamFieldValues::values.";
+ return false;
+ }
+ return true;
} else if (s.values.size() == 0) {
d->values.reset();
- return C2_OK;
+ return true;
}
- ALOGE("Multiple FieldSupportedValues objects. "
- "(Only one is allowed.)");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Invalid ParamFieldValues: "
+ "Two or more FieldSupportedValues objects exist in "
+ "ParamFieldValues. "
+ "Only zero or one is allowed.";
+ return false;
}
} // unnamed namespace
// C2SettingResult -> SettingResult
-Status objcpy(SettingResult *d, const C2SettingResult &s) {
- d->failureOther = static_cast<uint32_t>(s.failure);
+bool objcpy(SettingResult *d, const C2SettingResult &s) {
switch (s.failure) {
- case C2SettingResult::READ_ONLY:
- d->failure = SettingResult::Failure::READ_ONLY;
- break;
- case C2SettingResult::MISMATCH:
- d->failure = SettingResult::Failure::MISMATCH;
- break;
- case C2SettingResult::BAD_VALUE:
- d->failure = SettingResult::Failure::BAD_VALUE;
- break;
case C2SettingResult::BAD_TYPE:
d->failure = SettingResult::Failure::BAD_TYPE;
break;
@@ -391,53 +462,61 @@
case C2SettingResult::BAD_INDEX:
d->failure = SettingResult::Failure::BAD_INDEX;
break;
+ case C2SettingResult::READ_ONLY:
+ d->failure = SettingResult::Failure::READ_ONLY;
+ break;
+ case C2SettingResult::MISMATCH:
+ d->failure = SettingResult::Failure::MISMATCH;
+ break;
+ case C2SettingResult::BAD_VALUE:
+ d->failure = SettingResult::Failure::BAD_VALUE;
+ break;
case C2SettingResult::CONFLICT:
d->failure = SettingResult::Failure::CONFLICT;
break;
case C2SettingResult::UNSUPPORTED:
d->failure = SettingResult::Failure::UNSUPPORTED;
break;
+ case C2SettingResult::INFO_BAD_VALUE:
+ d->failure = SettingResult::Failure::INFO_BAD_VALUE;
+ break;
case C2SettingResult::INFO_CONFLICT:
d->failure = SettingResult::Failure::INFO_CONFLICT;
break;
default:
- d->failure = SettingResult::Failure::OTHER;
+ LOG(DEBUG) << "Unrecognized C2SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ d->failure = static_cast<SettingResult::Failure>(s.failure);
}
- Status status = objcpy(&d->field, s.field);
- if (status != Status::OK) {
- return status;
+ if (!objcpy(&d->field, s.field)) {
+ LOG(ERROR) << "Invalid C2SettingResult::field.";
+ return false;
}
d->conflicts.resize(s.conflicts.size());
size_t i = 0;
for (const C2ParamFieldValues& sConflict : s.conflicts) {
ParamFieldValues &dConflict = d->conflicts[i++];
- status = objcpy(&dConflict, sConflict);
- if (status != Status::OK) {
- return status;
+ if (!objcpy(&dConflict, sConflict)) {
+ LOG(ERROR) << "Invalid C2SettingResult::conflicts["
+ << i - 1 << "].";
+ return false;
}
}
- return Status::OK;
+ return true;
}
// SettingResult -> std::unique_ptr<C2SettingResult>
-c2_status_t objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
+bool objcpy(std::unique_ptr<C2SettingResult> *d, const SettingResult &s) {
*d = std::unique_ptr<C2SettingResult>(new C2SettingResult {
.field = C2ParamFieldValues(C2ParamFieldBuilder()) });
if (!*d) {
- return C2_NO_MEMORY;
+ LOG(ERROR) << "No memory for C2SettingResult.";
+ return false;
}
// failure
switch (s.failure) {
- case SettingResult::Failure::READ_ONLY:
- (*d)->failure = C2SettingResult::READ_ONLY;
- break;
- case SettingResult::Failure::MISMATCH:
- (*d)->failure = C2SettingResult::MISMATCH;
- break;
- case SettingResult::Failure::BAD_VALUE:
- (*d)->failure = C2SettingResult::BAD_VALUE;
- break;
case SettingResult::Failure::BAD_TYPE:
(*d)->failure = C2SettingResult::BAD_TYPE;
break;
@@ -447,23 +526,38 @@
case SettingResult::Failure::BAD_INDEX:
(*d)->failure = C2SettingResult::BAD_INDEX;
break;
+ case SettingResult::Failure::READ_ONLY:
+ (*d)->failure = C2SettingResult::READ_ONLY;
+ break;
+ case SettingResult::Failure::MISMATCH:
+ (*d)->failure = C2SettingResult::MISMATCH;
+ break;
+ case SettingResult::Failure::BAD_VALUE:
+ (*d)->failure = C2SettingResult::BAD_VALUE;
+ break;
case SettingResult::Failure::CONFLICT:
(*d)->failure = C2SettingResult::CONFLICT;
break;
case SettingResult::Failure::UNSUPPORTED:
(*d)->failure = C2SettingResult::UNSUPPORTED;
break;
+ case SettingResult::Failure::INFO_BAD_VALUE:
+ (*d)->failure = C2SettingResult::INFO_BAD_VALUE;
+ break;
case SettingResult::Failure::INFO_CONFLICT:
(*d)->failure = C2SettingResult::INFO_CONFLICT;
break;
default:
- (*d)->failure = static_cast<C2SettingResult::Failure>(s.failureOther);
+ LOG(DEBUG) << "Unrecognized SettingResult::Failure "
+ << "with underlying value " << underlying_value(s.failure)
+ << ".";
+ (*d)->failure = static_cast<C2SettingResult::Failure>(s.failure);
}
// field
- c2_status_t status = objcpy(&(*d)->field, s.field);
- if (status != C2_OK) {
- return status;
+ if (!objcpy(&(*d)->field, s.field)) {
+ LOG(ERROR) << "Invalid SettingResult::field.";
+ return false;
}
// conflicts
@@ -472,26 +566,26 @@
for (const ParamFieldValues& sConflict : s.conflicts) {
(*d)->conflicts.emplace_back(
C2ParamFieldValues{ C2ParamFieldBuilder(), nullptr });
- status = objcpy(&(*d)->conflicts.back(), sConflict);
- if (status != C2_OK) {
- return status;
+ if (!objcpy(&(*d)->conflicts.back(), sConflict)) {
+ LOG(ERROR) << "Invalid SettingResult::conflicts.";
+ return false;
}
}
- return C2_OK;
+ return true;
}
// C2ParamDescriptor -> ParamDescriptor
-Status objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
+bool objcpy(ParamDescriptor *d, const C2ParamDescriptor &s) {
d->index = static_cast<ParamIndex>(s.index());
d->attrib = static_cast<hidl_bitfield<ParamDescriptor::Attrib>>(
_C2ParamInspector::GetAttrib(s));
d->name = s.name();
copyVector<uint32_t>(&d->dependencies, s.dependencies());
- return Status::OK;
+ return true;
}
// ParamDescriptor -> C2ParamDescriptor
-c2_status_t objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
+bool objcpy(std::shared_ptr<C2ParamDescriptor> *d, const ParamDescriptor &s) {
std::vector<C2Param::Index> dDependencies;
dDependencies.reserve(s.dependencies.size());
for (const ParamIndex& sDependency : s.dependencies) {
@@ -502,11 +596,11 @@
static_cast<C2ParamDescriptor::attrib_t>(s.attrib),
C2String(s.name.c_str()),
std::move(dDependencies));
- return C2_OK;
+ return true;
}
// C2StructDescriptor -> StructDescriptor
-Status objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
+bool objcpy(StructDescriptor *d, const C2StructDescriptor &s) {
d->type = static_cast<ParamIndex>(s.coreIndex().coreIndex());
d->fields.resize(s.numFields());
size_t i = 0;
@@ -518,7 +612,7 @@
_C2ParamInspector::GetSize(sField));
dField.type = static_cast<hidl_bitfield<FieldDescriptor::Type>>(
sField.type());
- dField.length = static_cast<uint32_t>(sField.extent());
+ dField.extent = static_cast<uint32_t>(sField.extent());
dField.name = static_cast<hidl_string>(sField.name());
const auto& sNamedValues = sField.namedValues();
dField.namedValues.resize(sNamedValues.size());
@@ -530,18 +624,18 @@
sNamedValue.second.u64);
}
}
- return Status::OK;
+ return true;
}
// StructDescriptor -> C2StructDescriptor
-c2_status_t objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
+bool objcpy(std::unique_ptr<C2StructDescriptor> *d, const StructDescriptor &s) {
C2Param::CoreIndex dIndex = C2Param::CoreIndex(static_cast<uint32_t>(s.type));
std::vector<C2FieldDescriptor> dFields;
dFields.reserve(s.fields.size());
for (const auto &sField : s.fields) {
C2FieldDescriptor dField = {
static_cast<uint32_t>(sField.type),
- sField.length,
+ sField.extent,
sField.name,
sField.fieldId.offset,
sField.fieldId.size };
@@ -557,7 +651,7 @@
}
*d = std::make_unique<C2StructDescriptor>(
_C2ParamInspector::CreateStructDescriptor(dIndex, std::move(dFields)));
- return C2_OK;
+ return true;
}
namespace /* unnamed */ {
@@ -565,14 +659,14 @@
// Find or add a hidl BaseBlock object from a given C2Handle* to a list and an
// associated map.
// Note: The handle is not cloned.
-Status _addBaseBlock(
+bool _addBaseBlock(
uint32_t* index,
const C2Handle* handle,
std::list<BaseBlock>* baseBlocks,
std::map<const void*, uint32_t>* baseBlockIndices) {
if (!handle) {
- ALOGE("addBaseBlock called on a null C2Handle.");
- return Status::BAD_VALUE;
+ LOG(ERROR) << "addBaseBlock called on a null C2Handle.";
+ return false;
}
auto it = baseBlockIndices->find(handle);
if (it != baseBlockIndices->end()) {
@@ -583,26 +677,25 @@
baseBlocks->emplace_back();
BaseBlock &dBaseBlock = baseBlocks->back();
- dBaseBlock.type = BaseBlock::Type::NATIVE;
// This does not clone the handle.
- dBaseBlock.nativeBlock =
- reinterpret_cast<const native_handle_t*>(handle);
+ dBaseBlock.nativeBlock(
+ reinterpret_cast<const native_handle_t*>(handle));
}
- return Status::OK;
+ return true;
}
// Find or add a hidl BaseBlock object from a given BufferPoolData to a list and
// an associated map.
-Status _addBaseBlock(
+bool _addBaseBlock(
uint32_t* index,
const std::shared_ptr<BufferPoolData> bpData,
BufferPoolSender* bufferPoolSender,
std::list<BaseBlock>* baseBlocks,
std::map<const void*, uint32_t>* baseBlockIndices) {
if (!bpData) {
- ALOGE("addBaseBlock called on a null BufferPoolData.");
- return Status::BAD_VALUE;
+ LOG(ERROR) << "addBaseBlock called on a null BufferPoolData.";
+ return false;
}
auto it = baseBlockIndices->find(bpData.get());
if (it != baseBlockIndices->end()) {
@@ -613,24 +706,26 @@
baseBlocks->emplace_back();
BaseBlock &dBaseBlock = baseBlocks->back();
- dBaseBlock.type = BaseBlock::Type::POOLED;
if (bufferPoolSender) {
+ BufferStatusMessage pooledBlock;
ResultStatus bpStatus = bufferPoolSender->send(
bpData,
- &dBaseBlock.pooledBlock);
+ &pooledBlock);
if (bpStatus != ResultStatus::OK) {
- ALOGE("Failed to send buffer with BufferPool. Error: %d.",
- static_cast<int>(bpStatus));
- return Status::BAD_VALUE;
+ LOG(ERROR) << "Failed to send buffer with BufferPool. Error: "
+ << static_cast<int32_t>(bpStatus)
+ << ".";
+ return false;
}
+ dBaseBlock.pooledBlock(pooledBlock);
}
}
- return Status::OK;
+ return true;
}
-Status addBaseBlock(
+bool addBaseBlock(
uint32_t* index,
const C2Handle* handle,
const std::shared_ptr<const _C2BlockPoolData>& blockPoolData,
@@ -649,8 +744,8 @@
std::shared_ptr<BufferPoolData> bpData;
if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData)
|| !bpData) {
- ALOGE("BufferPoolData unavailable in a block.");
- return Status::BAD_VALUE;
+ LOG(ERROR) << "BufferPoolData unavailable in a block.";
+ return false;
}
return _addBaseBlock(
index, bpData,
@@ -662,69 +757,76 @@
index, handle,
baseBlocks, baseBlockIndices);
default:
- ALOGE("Unknown C2BlockPoolData type.");
- return Status::BAD_VALUE;
+ LOG(ERROR) << "Unknown C2BlockPoolData type.";
+ return false;
}
}
// C2Fence -> hidl_handle
// Note: File descriptors are not duplicated. The original file descriptor must
// not be closed before the transaction is complete.
-Status objcpy(hidl_handle* d, const C2Fence& s) {
+bool objcpy(hidl_handle* d, const C2Fence& s) {
(void)s; // TODO: implement s.fd()
int fenceFd = -1;
d->setTo(nullptr);
if (fenceFd >= 0) {
native_handle_t *handle = native_handle_create(1, 0);
if (!handle) {
- return Status::NO_MEMORY;
+ LOG(ERROR) << "Failed to create a native handle.";
+ return false;
}
handle->data[0] = fenceFd;
d->setTo(handle, true /* owns */);
}
- return Status::OK;
+ return true;
}
// C2ConstLinearBlock -> Block
// Note: Native handles are not duplicated. The original handles must not be
// closed before the transaction is complete.
-Status objcpy(Block* d, const C2ConstLinearBlock& s,
+bool objcpy(Block* d, const C2ConstLinearBlock& s,
BufferPoolSender* bufferPoolSender,
std::list<BaseBlock>* baseBlocks,
std::map<const void*, uint32_t>* baseBlockIndices) {
std::shared_ptr<const _C2BlockPoolData> bpData =
_C2BlockFactory::GetLinearBlockPoolData(s);
- Status status = addBaseBlock(&d->index, s.handle(), bpData,
- bufferPoolSender, baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstLinearBlock.";
+ return false;
}
// Create the metadata.
C2Hidl_RangeInfo dRangeInfo;
dRangeInfo.offset = static_cast<uint32_t>(s.offset());
dRangeInfo.length = static_cast<uint32_t>(s.size());
- status = createParamsBlob(&d->meta,
- std::vector<C2Param*>{ &dRangeInfo });
- if (status != Status::OK) {
- return Status::BAD_VALUE;
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRangeInfo })) {
+ LOG(ERROR) << "Invalid range info in C2ConstLinearBlock.";
+ return false;
}
// Copy the fence
- return objcpy(&d->fence, s.fence());
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstLinearBlock::fence.";
+ return false;
+ }
+ return true;
}
// C2ConstGraphicBlock -> Block
// Note: Native handles are not duplicated. The original handles must not be
// closed before the transaction is complete.
-Status objcpy(Block* d, const C2ConstGraphicBlock& s,
+bool objcpy(Block* d, const C2ConstGraphicBlock& s,
BufferPoolSender* bufferPoolSender,
std::list<BaseBlock>* baseBlocks,
std::map<const void*, uint32_t>* baseBlockIndices) {
std::shared_ptr<const _C2BlockPoolData> bpData =
_C2BlockFactory::GetGraphicBlockPoolData(s);
- Status status = addBaseBlock(&d->index, s.handle(), bpData,
- bufferPoolSender, baseBlocks, baseBlockIndices);
+ if (!addBaseBlock(&d->index, s.handle(), bpData,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid block data in C2ConstGraphicBlock.";
+ return false;
+ }
// Create the metadata.
C2Hidl_RectInfo dRectInfo;
@@ -733,62 +835,70 @@
dRectInfo.top = static_cast<uint32_t>(sRect.top);
dRectInfo.width = static_cast<uint32_t>(sRect.width);
dRectInfo.height = static_cast<uint32_t>(sRect.height);
- status = createParamsBlob(&d->meta,
- std::vector<C2Param*>{ &dRectInfo });
- if (status != Status::OK) {
- return Status::BAD_VALUE;
+ if (!createParamsBlob(&d->meta, std::vector<C2Param*>{ &dRectInfo })) {
+ LOG(ERROR) << "Invalid rect info in C2ConstGraphicBlock.";
+ return false;
}
// Copy the fence
- return objcpy(&d->fence, s.fence());
+ if (!objcpy(&d->fence, s.fence())) {
+ LOG(ERROR) << "Invalid C2ConstGraphicBlock::fence.";
+ return false;
+ }
+ return true;
}
// C2BufferData -> Buffer
// This function only fills in d->blocks.
-Status objcpy(Buffer* d, const C2BufferData& s,
+bool objcpy(Buffer* d, const C2BufferData& s,
BufferPoolSender* bufferPoolSender,
std::list<BaseBlock>* baseBlocks,
std::map<const void*, uint32_t>* baseBlockIndices) {
- Status status;
d->blocks.resize(
s.linearBlocks().size() +
s.graphicBlocks().size());
size_t i = 0;
for (const C2ConstLinearBlock& linearBlock : s.linearBlocks()) {
Block& dBlock = d->blocks[i++];
- status = objcpy(
+ if (!objcpy(
&dBlock, linearBlock,
- bufferPoolSender, baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::linearBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
}
}
for (const C2ConstGraphicBlock& graphicBlock : s.graphicBlocks()) {
Block& dBlock = d->blocks[i++];
- status = objcpy(
+ if (!objcpy(
&dBlock, graphicBlock,
- bufferPoolSender, baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2BufferData::graphicBlocks. "
+ << "(Destination index = " << i - 1 << ".)";
+ return false;
}
}
- return Status::OK;
+ return true;
}
// C2Buffer -> Buffer
-Status objcpy(Buffer* d, const C2Buffer& s,
+bool objcpy(Buffer* d, const C2Buffer& s,
BufferPoolSender* bufferPoolSender,
std::list<BaseBlock>* baseBlocks,
std::map<const void*, uint32_t>* baseBlockIndices) {
- Status status = createParamsBlob(&d->info, s.info());
- if (status != Status::OK) {
- return status;
+ if (!createParamsBlob(&d->info, s.info())) {
+ LOG(ERROR) << "Invalid C2Buffer::info.";
+ return false;
}
- return objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices);
+ if (!objcpy(d, s.data(), bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Buffer::data.";
+ return false;
+ }
+ return true;
}
// C2InfoBuffer -> InfoBuffer
-Status objcpy(InfoBuffer* d, const C2InfoBuffer& s,
+bool objcpy(InfoBuffer* d, const C2InfoBuffer& s,
BufferPoolSender* bufferPoolSender,
std::list<BaseBlock>* baseBlocks,
std::map<const void*, uint32_t>* baseBlockIndices) {
@@ -798,24 +908,21 @@
(void)bufferPoolSender;
(void)baseBlocks;
(void)baseBlockIndices;
- return Status::OK;
- /*
- // Stub implementation that may work in the future.
- d->index = static_cast<uint32_t>(s.index());
- d->buffer.info.resize(0);
- return objcpy(&d->buffer, s.data(), baseBlocks, baseBlockIndices);
- */
+ LOG(INFO) << "InfoBuffer not implemented.";
+ return true;
}
// C2FrameData -> FrameData
-Status objcpy(FrameData* d, const C2FrameData& s,
+bool objcpy(FrameData* d, const C2FrameData& s,
BufferPoolSender* bufferPoolSender,
std::list<BaseBlock>* baseBlocks,
std::map<const void*, uint32_t>* baseBlockIndices) {
d->flags = static_cast<hidl_bitfield<FrameData::Flags>>(s.flags);
- objcpy(&d->ordinal, s.ordinal);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid C2FrameData::ordinal.";
+ return false;
+ }
- Status status;
d->buffers.resize(s.buffers.size());
size_t i = 0;
for (const std::shared_ptr<C2Buffer>& sBuffer : s.buffers) {
@@ -827,17 +934,18 @@
dBuffer.blocks.resize(0);
continue;
}
- status = objcpy(
+ if (!objcpy(
&dBuffer, *sBuffer,
- bufferPoolSender, baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::buffers["
+ << i - 1 << "].";
+ return false;
}
}
- status = createParamsBlob(&d->configUpdate, s.configUpdate);
- if (status != Status::OK) {
- return status;
+ if (!createParamsBlob(&d->configUpdate, s.configUpdate)) {
+ LOG(ERROR) << "Invalid C2FrameData::configUpdate.";
+ return false;
}
d->infoBuffers.resize(s.infoBuffers.size());
@@ -845,17 +953,19 @@
for (const std::shared_ptr<C2InfoBuffer>& sInfoBuffer : s.infoBuffers) {
InfoBuffer& dInfoBuffer = d->infoBuffers[i++];
if (!sInfoBuffer) {
- ALOGE("Null C2InfoBuffer");
- return Status::BAD_VALUE;
+ LOG(ERROR) << "Null C2FrameData::infoBuffers["
+ << i - 1 << "].";
+ return false;
}
- status = objcpy(&dInfoBuffer, *sInfoBuffer,
- bufferPoolSender, baseBlocks, baseBlockIndices);
- if (status != Status::OK) {
- return status;
+ if (!objcpy(&dInfoBuffer, *sInfoBuffer,
+ bufferPoolSender, baseBlocks, baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2FrameData::infoBuffers["
+ << i - 1 << "].";
+ return false;
}
}
- return status;
+ return true;
}
} // unnamed namespace
@@ -885,7 +995,7 @@
const std::shared_ptr<BufferPoolData>& bpData,
BufferStatusMessage* bpMessage) {
if (!mReceiverManager) {
- ALOGE("No access to receiver's BufferPool.");
+ LOG(ERROR) << "No access to receiver's BufferPool.";
return ResultStatus::NOT_FOUND;
}
ResultStatus rs;
@@ -893,7 +1003,7 @@
if (!mSenderManager) {
mSenderManager = ClientManager::getInstance();
if (!mSenderManager) {
- ALOGE("Failed to retrieve local BufferPool ClientManager.");
+ LOG(ERROR) << "Failed to retrieve local BufferPool ClientManager.";
return ResultStatus::CRITICAL_ERROR;
}
}
@@ -915,11 +1025,11 @@
connectionId,
&receiverConnectionId);
if ((rs != ResultStatus::OK) && (rs != ResultStatus::ALREADY_EXISTS)) {
- ALOGW("registerSender -- returned error: %d.",
- static_cast<int>(rs));
+ LOG(WARNING) << "registerSender -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
return rs;
} else {
- ALOGV("registerSender -- succeeded.");
mReceiverConnectionId = receiverConnectionId;
}
}
@@ -929,12 +1039,13 @@
rs = mSenderManager->postSend(
mReceiverConnectionId, bpData, &transactionId, ×tampUs);
if (rs != ResultStatus::OK) {
- ALOGE("ClientManager::postSend -- returned error: %d.",
- static_cast<int>(rs));
+ LOG(ERROR) << "ClientManager::postSend -- returned error: "
+ << static_cast<int32_t>(rs)
+ << ".";
return rs;
}
if (!bpMessage) {
- ALOGE("Null output parameter for BufferStatusMessage.");
+ LOG(ERROR) << "Null output parameter for BufferStatusMessage.";
return ResultStatus::CRITICAL_ERROR;
}
bpMessage->connectionId = mReceiverConnectionId;
@@ -946,12 +1057,10 @@
}
// std::list<std::unique_ptr<C2Work>> -> WorkBundle
-Status objcpy(
+bool objcpy(
WorkBundle* d,
const std::list<std::unique_ptr<C2Work>>& s,
BufferPoolSender* bufferPoolSender) {
- Status status = Status::OK;
-
// baseBlocks holds a list of BaseBlock objects that Blocks can refer to.
std::list<BaseBlock> baseBlocks;
@@ -971,63 +1080,80 @@
for (const std::unique_ptr<C2Work>& sWork : s) {
Work &dWork = d->works[i++];
if (!sWork) {
- ALOGW("Null C2Work encountered.");
+ LOG(WARNING) << "Null C2Work encountered.";
continue;
}
- status = objcpy(&dWork.input, sWork->input,
- bufferPoolSender, &baseBlocks, &baseBlockIndices);
- if (status != Status::OK) {
- return status;
+
+ // chain info is not in use currently.
+
+ // input
+ if (!objcpy(&dWork.input, sWork->input,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::input.";
+ return false;
}
+
+ // worklets
if (sWork->worklets.size() == 0) {
- ALOGW("Work with no worklets.");
+ LOG(DEBUG) << "Work with no worklets.";
} else {
- if (sWork->worklets.size() > 1) {
- ALOGW("Work with multiple worklets. "
- "Only the first worklet will be marshalled.");
- }
- if (!sWork->worklets.front()) {
- ALOGE("Null worklet encountered.");
- return Status::BAD_VALUE;
- }
-
- // Parcel the first worklet.
- const C2Worklet &sWorklet = *sWork->worklets.front();
- Worklet &dWorklet = dWork.worklet;
-
- dWorklet.tunings.resize(sWorklet.tunings.size());
+ // Parcel the worklets.
+ hidl_vec<Worklet> &dWorklets = dWork.worklets;
+ dWorklets.resize(sWork->worklets.size());
size_t j = 0;
- for (const std::unique_ptr<C2Tuning>& sTuning : sWorklet.tunings) {
- status = createParamsBlob(
- &dWorklet.tunings[j++],
- std::vector<C2Param*>
- { reinterpret_cast<C2Param*>(sTuning.get()) });
- if (status != Status::OK) {
- return status;
+ for (const std::unique_ptr<C2Worklet>& sWorklet : sWork->worklets)
+ {
+ if (!sWorklet) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j << "].";
+ continue;
}
- }
+ Worklet &dWorklet = dWorklets[j++];
- dWorklet.failures.resize(sWorklet.failures.size());
- j = 0;
- for (const std::unique_ptr<C2SettingResult>& sFailure :
- sWorklet.failures) {
- if (!sFailure) {
- ALOGE("Null C2SettingResult");
- return Status::BAD_VALUE;
- }
- status = objcpy(&dWorklet.failures[j++], *sFailure);
- if (status != Status::OK) {
- return status;
- }
- }
+ // component id
+ dWorklet.componentId = static_cast<uint32_t>(
+ sWorklet->component);
- status = objcpy(&dWorklet.output, sWorklet.output,
- bufferPoolSender, &baseBlocks, &baseBlockIndices);
- if (status != Status::OK) {
- return status;
+ // tunings
+ if (!createParamsBlob(&dWorklet.tunings, sWorklet->tunings)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->tunings.";
+ return false;
+ }
+
+ // failures
+ dWorklet.failures.resize(sWorklet->failures.size());
+ size_t k = 0;
+ for (const std::unique_ptr<C2SettingResult>& sFailure :
+ sWorklet->failures) {
+ if (!sFailure) {
+ LOG(WARNING) << "Null C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k << "].";
+ continue;
+ }
+ if (!objcpy(&dWorklet.failures[k++], *sFailure)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->failures["
+ << k - 1 << "].";
+ return false;
+ }
+ }
+
+ // output
+ if (!objcpy(&dWorklet.output, sWorklet->output,
+ bufferPoolSender, &baseBlocks, &baseBlockIndices)) {
+ LOG(ERROR) << "Invalid C2Work::worklets["
+ << j - 1 << "]->output.";
+ return false;
+ }
}
}
- dWork.workletProcessed = sWork->workletsProcessed > 0;
+
+ // worklets processed
+ dWork.workletsProcessed = sWork->workletsProcessed;
+
+ // result
dWork.result = static_cast<Status>(sWork->result);
}
@@ -1040,7 +1166,7 @@
}
}
- return Status::OK;
+ return true;
}
namespace /* unnamed */ {
@@ -1058,15 +1184,15 @@
// hidl_handle -> C2Fence
// Note: File descriptors are not duplicated. The original file descriptor must
// not be closed before the transaction is complete.
-c2_status_t objcpy(C2Fence* d, const hidl_handle& s) {
+bool objcpy(C2Fence* d, const hidl_handle& s) {
// TODO: Implement.
(void)s;
*d = C2Fence();
- return C2_OK;
+ return true;
}
// C2LinearBlock, vector<C2Param*>, C2Fence -> C2Buffer
-c2_status_t createLinearBuffer(
+bool createLinearBuffer(
std::shared_ptr<C2Buffer>* buffer,
const std::shared_ptr<C2LinearBlock>& block,
const std::vector<C2Param*>& meta,
@@ -1074,12 +1200,12 @@
// Check the block meta. It should have exactly 1 C2Info:
// C2Hidl_RangeInfo.
if ((meta.size() != 1) || !meta[0]) {
- ALOGE("Invalid block metadata for ion block.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Invalid C2LinearBlock::meta.";
+ return false;
}
if (meta[0]->size() != sizeof(C2Hidl_RangeInfo)) {
- ALOGE("Invalid block metadata for ion block: range.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Invalid range info in C2LinearBlock.";
+ return false;
}
C2Hidl_RangeInfo *rangeInfo =
reinterpret_cast<C2Hidl_RangeInfo*>(meta[0]);
@@ -1089,14 +1215,14 @@
rangeInfo->offset, rangeInfo->length,
fence));
if (!(*buffer)) {
- ALOGE("Cannot create a linear buffer.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "CreateLinearBuffer failed.";
+ return false;
}
- return C2_OK;
+ return true;
}
// C2GraphicBlock, vector<C2Param*>, C2Fence -> C2Buffer
-c2_status_t createGraphicBuffer(
+bool createGraphicBuffer(
std::shared_ptr<C2Buffer>* buffer,
const std::shared_ptr<C2GraphicBlock>& block,
const std::vector<C2Param*>& meta,
@@ -1104,12 +1230,12 @@
// Check the block meta. It should have exactly 1 C2Info:
// C2Hidl_RectInfo.
if ((meta.size() != 1) || !meta[0]) {
- ALOGE("Invalid block metadata for graphic block.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Invalid C2GraphicBlock::meta.";
+ return false;
}
if (meta[0]->size() != sizeof(C2Hidl_RectInfo)) {
- ALOGE("Invalid block metadata for graphic block: crop rect.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Invalid rect info in C2GraphicBlock.";
+ return false;
}
C2Hidl_RectInfo *rectInfo =
reinterpret_cast<C2Hidl_RectInfo*>(meta[0]);
@@ -1120,136 +1246,144 @@
at(rectInfo->left, rectInfo->top),
fence));
if (!(*buffer)) {
- ALOGE("Cannot create a graphic buffer.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "CreateGraphicBuffer failed.";
+ return false;
}
- return C2_OK;
+ return true;
}
// Buffer -> C2Buffer
// Note: The native handles will be cloned.
-c2_status_t objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
+bool objcpy(std::shared_ptr<C2Buffer>* d, const Buffer& s,
const std::vector<C2BaseBlock>& baseBlocks) {
- c2_status_t status;
*d = nullptr;
// Currently, a non-null C2Buffer must contain exactly 1 block.
if (s.blocks.size() == 0) {
- return C2_OK;
+ return true;
} else if (s.blocks.size() != 1) {
- ALOGE("Currently, a C2Buffer must contain exactly 1 block.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Invalid Buffer: "
+ "Currently, a C2Buffer must contain exactly 1 block.";
+ return false;
}
const Block &sBlock = s.blocks[0];
if (sBlock.index >= baseBlocks.size()) {
- ALOGE("Index into baseBlocks is out of range.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Invalid Buffer::blocks[0].index: "
+ "Array index out of range.";
+ return false;
}
const C2BaseBlock &baseBlock = baseBlocks[sBlock.index];
// Parse meta.
std::vector<C2Param*> sBlockMeta;
- status = parseParamsBlob(&sBlockMeta, sBlock.meta);
- if (status != C2_OK) {
- ALOGE("Invalid block params blob.");
- return C2_BAD_VALUE;
+ if (!parseParamsBlob(&sBlockMeta, sBlock.meta)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].meta.";
+ return false;
}
// Copy fence.
C2Fence dFence;
- status = objcpy(&dFence, sBlock.fence);
+ if (!objcpy(&dFence, sBlock.fence)) {
+ LOG(ERROR) << "Invalid Buffer::blocks[0].fence.";
+ return false;
+ }
// Construct a block.
switch (baseBlock.type) {
case C2BaseBlock::LINEAR:
- status = createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence);
+ if (!createLinearBuffer(d, baseBlock.linear, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::linear.";
+ return false;
+ }
break;
case C2BaseBlock::GRAPHIC:
- status = createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence);
+ if (!createGraphicBuffer(d, baseBlock.graphic, sBlockMeta, dFence)) {
+ LOG(ERROR) << "Invalid C2BaseBlock::graphic.";
+ return false;
+ }
break;
default:
- ALOGE("Invalid BaseBlock type.");
- return C2_BAD_VALUE;
- }
- if (status != C2_OK) {
- return status;
+ LOG(ERROR) << "Invalid C2BaseBlock::type.";
+ return false;
}
// Parse info
std::vector<C2Param*> params;
- status = parseParamsBlob(¶ms, s.info);
- if (status != C2_OK) {
- ALOGE("Invalid buffer params blob.");
- return status;
+ if (!parseParamsBlob(¶ms, s.info)) {
+ LOG(ERROR) << "Invalid Buffer::info.";
+ return false;
}
for (C2Param* param : params) {
if (param == nullptr) {
- ALOGE("Null buffer param encountered.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Null param in Buffer::info.";
+ return false;
}
- std::shared_ptr<C2Param> c2param(
- C2Param::Copy(*param).release());
+ std::shared_ptr<C2Param> c2param{
+ C2Param::Copy(*param).release()};
if (!c2param) {
- ALOGE("Invalid buffer param inside a blob.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Invalid param in Buffer::info.";
+ return false;
}
- status = (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
+ c2_status_t status =
+ (*d)->setInfo(std::static_pointer_cast<C2Info>(c2param));
if (status != C2_OK) {
- ALOGE("C2Buffer::setInfo failed().");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "C2Buffer::setInfo failed.";
+ return false;
}
}
- return C2_OK;
+ return true;
}
// FrameData -> C2FrameData
-c2_status_t objcpy(C2FrameData* d, const FrameData& s,
+bool objcpy(C2FrameData* d, const FrameData& s,
const std::vector<C2BaseBlock>& baseBlocks) {
- c2_status_t status;
d->flags = static_cast<C2FrameData::flags_t>(s.flags);
- objcpy(&d->ordinal, s.ordinal);
+ if (!objcpy(&d->ordinal, s.ordinal)) {
+ LOG(ERROR) << "Invalid FrameData::ordinal.";
+ return false;
+ }
d->buffers.clear();
d->buffers.reserve(s.buffers.size());
for (const Buffer& sBuffer : s.buffers) {
std::shared_ptr<C2Buffer> dBuffer;
- status = objcpy(&dBuffer, sBuffer, baseBlocks);
- if (status != C2_OK) {
- return status;
+ if (!objcpy(&dBuffer, sBuffer, baseBlocks)) {
+ LOG(ERROR) << "Invalid FrameData::buffers.";
+ return false;
}
d->buffers.emplace_back(dBuffer);
}
std::vector<C2Param*> params;
- status = parseParamsBlob(¶ms, s.configUpdate);
- if (status != C2_OK) {
- ALOGE("Failed to parse frame data params.");
- return status;
+ if (!parseParamsBlob(¶ms, s.configUpdate)) {
+ LOG(ERROR) << "Invalid FrameData::configUpdate.";
+ return false;
}
d->configUpdate.clear();
for (C2Param* param : params) {
d->configUpdate.emplace_back(C2Param::Copy(*param));
if (!d->configUpdate.back()) {
- ALOGE("Unexpected error while parsing frame data params.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Unexpected error while parsing "
+ "FrameData::configUpdate.";
+ return false;
}
}
// TODO: Implement this once C2InfoBuffer has constructors.
d->infoBuffers.clear();
- return C2_OK;
+ return true;
}
// BaseBlock -> C2BaseBlock
-c2_status_t objcpy(C2BaseBlock* d, const BaseBlock& s) {
- switch (s.type) {
- case BaseBlock::Type::NATIVE: {
+bool objcpy(C2BaseBlock* d, const BaseBlock& s) {
+ switch (s.getDiscriminator()) {
+ case BaseBlock::hidl_discriminator::nativeBlock: {
native_handle_t* sHandle =
- native_handle_clone(s.nativeBlock);
+ native_handle_clone(s.nativeBlock());
if (sHandle == nullptr) {
- ALOGE("Null native handle in a block.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Null BaseBlock::nativeBlock.";
+ return false;
}
const C2Handle *sC2Handle =
reinterpret_cast<const C2Handle*>(sHandle);
@@ -1257,25 +1391,25 @@
d->linear = _C2BlockFactory::CreateLinearBlock(sC2Handle);
if (d->linear) {
d->type = C2BaseBlock::LINEAR;
- return C2_OK;
+ return true;
}
d->graphic = _C2BlockFactory::CreateGraphicBlock(sC2Handle);
if (d->graphic) {
d->type = C2BaseBlock::GRAPHIC;
- return C2_OK;
+ return true;
}
- ALOGE("Unknown handle type in native BaseBlock.");
+ LOG(ERROR) << "Unknown handle type in BaseBlock::nativeBlock.";
if (sHandle) {
native_handle_close(sHandle);
native_handle_delete(sHandle);
}
- return C2_BAD_VALUE;
+ return false;
}
- case BaseBlock::Type::POOLED: {
+ case BaseBlock::hidl_discriminator::pooledBlock: {
const BufferStatusMessage &bpMessage =
- s.pooledBlock;
+ s.pooledBlock();
sp<ClientManager> bp = ClientManager::getInstance();
std::shared_ptr<BufferPoolData> bpData;
native_handle_t *cHandle;
@@ -1287,48 +1421,49 @@
&cHandle,
&bpData);
if (bpStatus != ResultStatus::OK) {
- ALOGE("Failed to receive buffer from bufferpool -- "
- "resultStatus = %d",
- static_cast<int>(bpStatus));
- return toC2Status(bpStatus);
+ LOG(ERROR) << "Failed to receive buffer from bufferpool -- "
+ << "resultStatus = " << underlying_value(bpStatus)
+ << ".";
+ return false;
} else if (!bpData) {
- ALOGE("No data in bufferpool transaction.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "No data in bufferpool transaction.";
+ return false;
}
d->linear = _C2BlockFactory::CreateLinearBlock(cHandle, bpData);
if (d->linear) {
d->type = C2BaseBlock::LINEAR;
- return C2_OK;
+ return true;
}
d->graphic = _C2BlockFactory::CreateGraphicBlock(cHandle, bpData);
if (d->graphic) {
d->type = C2BaseBlock::GRAPHIC;
- return C2_OK;
+ return true;
}
- ALOGE("Unknown handle type in pooled BaseBlock.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
+ return false;
}
default:
- ALOGE("Corrupted BaseBlock type: %d", static_cast<int>(s.type));
- return C2_BAD_VALUE;
+ LOG(ERROR) << "Unrecognized BaseBlock's discriminator with "
+ << "underlying value "
+ << underlying_value(s.getDiscriminator()) << ".";
+ return false;
}
}
} // unnamed namespace
// WorkBundle -> std::list<std::unique_ptr<C2Work>>
-c2_status_t objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
- c2_status_t status;
-
+bool objcpy(std::list<std::unique_ptr<C2Work>>* d, const WorkBundle& s) {
// Convert BaseBlocks to C2BaseBlocks.
std::vector<C2BaseBlock> dBaseBlocks(s.baseBlocks.size());
for (size_t i = 0; i < s.baseBlocks.size(); ++i) {
- status = objcpy(&dBaseBlocks[i], s.baseBlocks[i]);
- if (status != C2_OK) {
- return status;
+ if (!objcpy(&dBaseBlocks[i], s.baseBlocks[i])) {
+ LOG(ERROR) << "Invalid WorkBundle::baseBlocks["
+ << i << "].";
+ return false;
}
}
@@ -1337,74 +1472,58 @@
d->emplace_back(std::make_unique<C2Work>());
C2Work& dWork = *d->back();
+ // chain info is not in use currently.
+
// input
- status = objcpy(&dWork.input, sWork.input, dBaseBlocks);
- if (status != C2_OK) {
- ALOGE("Error constructing C2Work's input.");
- return C2_BAD_VALUE;
+ if (!objcpy(&dWork.input, sWork.input, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Work::input.";
+ return false;
}
// worklet(s)
dWork.worklets.clear();
- // TODO: Currently, tunneling is not supported.
- if (sWork.workletProcessed) {
- dWork.workletsProcessed = 1;
-
- const Worklet &sWorklet = sWork.worklet;
+ for (const Worklet& sWorklet : sWork.worklets) {
std::unique_ptr<C2Worklet> dWorklet = std::make_unique<C2Worklet>();
+ // component id
+ dWorklet->component = static_cast<c2_node_id_t>(
+ sWorklet.componentId);
+
// tunings
- dWorklet->tunings.clear();
- dWorklet->tunings.reserve(sWorklet.tunings.size());
- for (const Params& sTuning : sWorklet.tunings) {
- std::vector<C2Param*> dParams;
- status = parseParamsBlob(&dParams, sTuning);
- if (status != C2_OK) {
- ALOGE("Failed to parse C2Tuning in C2Worklet.");
- return C2_BAD_VALUE;
- }
- for (C2Param* param : dParams) {
- std::unique_ptr<C2Param> dParam = C2Param::Copy(*param);
- if (!dParam) {
- ALOGE("Null C2Tuning encountered while "
- "parsing C2Worklet.");
- return C2_BAD_VALUE;
- }
- dWorklet->tunings.emplace_back(
- std::unique_ptr<C2Tuning>(
- reinterpret_cast<C2Tuning*>(
- dParam.release())));
- }
+ if (!copyParamsFromBlob(&dWorklet->tunings, sWorklet.tunings)) {
+ LOG(ERROR) << "Invalid Worklet::tunings";
+ return false;
}
+
// failures
dWorklet->failures.clear();
dWorklet->failures.reserve(sWorklet.failures.size());
for (const SettingResult& sFailure : sWorklet.failures) {
std::unique_ptr<C2SettingResult> dFailure;
- status = objcpy(&dFailure, sFailure);
- if (status != C2_OK) {
- ALOGE("Failed to create C2SettingResult in C2Worklet.");
- return C2_BAD_VALUE;
+ if (!objcpy(&dFailure, sFailure)) {
+ LOG(ERROR) << "Invalid Worklet::failures.";
+ return false;
}
dWorklet->failures.emplace_back(std::move(dFailure));
}
+
// output
- status = objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks);
- if (status != C2_OK) {
- ALOGE("Failed to create output C2FrameData.");
- return C2_BAD_VALUE;
+ if (!objcpy(&dWorklet->output, sWorklet.output, dBaseBlocks)) {
+ LOG(ERROR) << "Invalid Worklet::output.";
+ return false;
}
+
dWork.worklets.emplace_back(std::move(dWorklet));
- } else {
- dWork.worklets.emplace_back(std::make_unique<C2Worklet>());
- dWork.workletsProcessed = 0;
}
+ // workletsProcessed
+ dWork.workletsProcessed = sWork.workletsProcessed;
+
// result
dWork.result = static_cast<c2_status_t>(sWork.result);
}
- return C2_OK;
+ return true;
}
constexpr size_t PARAMS_ALIGNMENT = 8; // 64-bit alignment
@@ -1413,7 +1532,7 @@
static_assert(PARAMS_ALIGNMENT % alignof(C2Tuning) == 0, "C2Param alignment mismatch");
// Params -> std::vector<C2Param*>
-c2_status_t parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
+bool parseParamsBlob(std::vector<C2Param*> *params, const hidl_vec<uint8_t> &blob) {
// assuming blob is const here
size_t size = blob.size();
size_t ix = 0;
@@ -1429,21 +1548,27 @@
}
} while (p);
- return ix == size ? C2_OK : C2_BAD_VALUE;
+ if (ix != size) {
+ LOG(ERROR) << "parseParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
}
namespace /* unnamed */ {
/**
- * Concatenates a list of C2Params into a params blob.
+ * Concatenates a list of C2Params into a params blob. T is a container type
+ * whose member type is compatible with C2Param*.
+ *
* \param[out] blob target blob
* \param[in] params parameters to concatenate
* \retval C2_OK if the blob was successfully created
- * \retval C2_BAD_VALUE if the blob was not successful (this only happens if the parameters were
- * not const)
+ * \retval C2_BAD_VALUE if the blob was not successful created (this only
+ * happens if the parameters were not const)
*/
-template<typename T>
-Status _createParamsBlob(hidl_vec<uint8_t> *blob, const T ¶ms) {
+template <typename T>
+bool _createParamsBlob(hidl_vec<uint8_t> *blob, const T ¶ms) {
// assuming the parameter values are const
size_t size = 0;
for (const auto &p : params) {
@@ -1469,77 +1594,106 @@
ix = align(ix, PARAMS_ALIGNMENT);
}
blob->resize(ix);
- return ix == size ? Status::OK : Status::CORRUPTED;
+ if (ix != size) {
+ LOG(ERROR) << "createParamsBlob -- inconsistent sizes.";
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Parses a params blob and create a vector of new T objects that contain copies
+ * of the params in the blob. T is C2Param or its compatible derived class.
+ *
+ * \param[out] params the resulting vector
+ * \param[in] blob parameter blob to parse
+ * \retval C2_OK if the full blob was parsed and params was constructed
+ * \retval C2_BAD_VALUE otherwise
+ */
+template <typename T>
+bool _copyParamsFromBlob(
+ std::vector<std::unique_ptr<T>>* params,
+ Params blob) {
+
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "copyParamsFromBlob -- failed to parse.";
+ return false;
+ }
+
+ params->resize(paramPointers.size());
+ size_t i = 0;
+ for (C2Param* const& paramPointer : paramPointers) {
+ if (!paramPointer) {
+ LOG(ERROR) << "copyParamsFromBlob -- null paramPointer.";
+ return false;
+ }
+ (*params)[i++].reset(reinterpret_cast<T*>(
+ C2Param::Copy(*paramPointer).release()));
+ }
+ return true;
}
} // unnamed namespace
// std::vector<const C2Param*> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<const C2Param*> ¶ms) {
return _createParamsBlob(blob, params);
}
// std::vector<C2Param*> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<C2Param*> ¶ms) {
return _createParamsBlob(blob, params);
}
// std::vector<std::unique_ptr<C2Param>> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<std::unique_ptr<C2Param>> ¶ms) {
return _createParamsBlob(blob, params);
}
// std::vector<std::unique_ptr<C2Tuning>> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<std::unique_ptr<C2Tuning>> ¶ms) {
return _createParamsBlob(blob, params);
}
// std::vector<std::shared_ptr<const C2Info>> -> Params
-Status createParamsBlob(
+bool createParamsBlob(
hidl_vec<uint8_t> *blob,
const std::vector<std::shared_ptr<const C2Info>> ¶ms) {
return _createParamsBlob(blob, params);
}
// Params -> std::vector<std::unique_ptr<C2Param>>
-c2_status_t copyParamsFromBlob(
+bool copyParamsFromBlob(
std::vector<std::unique_ptr<C2Param>>* params,
Params blob) {
- std::vector<C2Param*> paramPointers;
- c2_status_t status = parseParamsBlob(¶mPointers, blob);
- if (status != C2_OK) {
- ALOGE("copyParamsFromBlob -- blob parsing failed.");
- return status;
- }
- params->resize(paramPointers.size());
- size_t i = 0;
- for (C2Param* const& paramPointer : paramPointers) {
- if (!paramPointer) {
- ALOGE("copyParamsFromBlob -- corrupted params blob.");
- return C2_BAD_VALUE;
- }
- (*params)[i++] = C2Param::Copy(*paramPointer);
- }
- return C2_OK;
+ return _copyParamsFromBlob(params, blob);
+}
+
+// Params -> std::vector<std::unique_ptr<C2Tuning>>
+bool copyParamsFromBlob(
+ std::vector<std::unique_ptr<C2Tuning>>* params,
+ Params blob) {
+ return _copyParamsFromBlob(params, blob);
}
// Params -> update std::vector<std::unique_ptr<C2Param>>
-c2_status_t updateParamsFromBlob(
+bool updateParamsFromBlob(
const std::vector<C2Param*>& params,
const Params& blob) {
std::unordered_map<uint32_t, C2Param*> index2param;
for (C2Param* const& param : params) {
if (!param) {
- ALOGE("updateParamsFromBlob -- corrupted input params.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "updateParamsFromBlob -- null output param.";
+ return false;
}
if (index2param.find(param->index()) == index2param.end()) {
index2param.emplace(param->index(), param);
@@ -1547,33 +1701,31 @@
}
std::vector<C2Param*> paramPointers;
- c2_status_t status = parseParamsBlob(¶mPointers, blob);
- if (status != C2_OK) {
- ALOGE("updateParamsFromBlob -- blob parsing failed.");
- return status;
+ if (!parseParamsBlob(¶mPointers, blob)) {
+ LOG(ERROR) << "updateParamsFromBlob -- failed to parse.";
+ return false;
}
for (C2Param* const& paramPointer : paramPointers) {
if (!paramPointer) {
- ALOGE("updateParamsFromBlob -- corrupted param in blob.");
- return C2_BAD_VALUE;
+ LOG(ERROR) << "updateParamsFromBlob -- null input param.";
+ return false;
}
decltype(index2param)::iterator i = index2param.find(
paramPointer->index());
if (i == index2param.end()) {
- ALOGW("updateParamsFromBlob -- unseen param index.");
+ LOG(DEBUG) << "updateParamsFromBlob -- index "
+ << paramPointer->index() << " not found. Skipping...";
continue;
}
if (!i->second->updateFrom(*paramPointer)) {
- ALOGE("updateParamsFromBlob -- mismatching sizes: "
- "%u vs %u (index = %u).",
- static_cast<unsigned>(params.size()),
- static_cast<unsigned>(paramPointer->size()),
- static_cast<unsigned>(i->first));
- return C2_BAD_VALUE;
+ LOG(ERROR) << "updateParamsFromBlob -- size mismatch: "
+ << params.size() << " vs " << paramPointer->size()
+ << " (index = " << i->first << ").";
+ return false;
}
}
- return C2_OK;
+ return true;
}
// Convert BufferPool ResultStatus to c2_status_t.
@@ -1590,7 +1742,8 @@
case ResultStatus::CRITICAL_ERROR:
return C2_CORRUPTED;
default:
- ALOGW("Unrecognized BufferPool ResultStatus: %d", static_cast<int>(rs));
+ LOG(WARNING) << "Unrecognized BufferPool ResultStatus: "
+ << static_cast<int32_t>(rs) << ".";
return C2_CORRUPTED;
}
}
@@ -1669,34 +1822,33 @@
uint32_t generation,
int32_t* bqSlot) {
if (!igbp) {
- ALOGW("attachToBufferQueue -- null producer.");
+ LOG(WARNING) << "attachToBufferQueue -- null producer.";
return NO_INIT;
}
sp<GraphicBuffer> graphicBuffer = createGraphicBuffer(block);
graphicBuffer->setGenerationNumber(generation);
- ALOGV("attachToBufferQueue -- attaching buffer: "
- "block dimension %ux%u, "
- "graphicBuffer dimension %ux%u, "
- "format %#x, usage %#llx, stride %u, generation %u.",
- static_cast<unsigned>(block.width()),
- static_cast<unsigned>(block.height()),
- static_cast<unsigned>(graphicBuffer->getWidth()),
- static_cast<unsigned>(graphicBuffer->getHeight()),
- static_cast<unsigned>(graphicBuffer->getPixelFormat()),
- static_cast<unsigned long long>(graphicBuffer->getUsage()),
- static_cast<unsigned>(graphicBuffer->getStride()),
- static_cast<unsigned>(graphicBuffer->getGenerationNumber()));
+ LOG(VERBOSE) << "attachToBufferQueue -- attaching buffer:"
+ << " block dimension " << block.width() << "x"
+ << block.height()
+ << ", graphicBuffer dimension " << graphicBuffer->getWidth() << "x"
+ << graphicBuffer->getHeight()
+ << std::hex << std::setfill('0')
+ << ", format 0x" << std::setw(8) << graphicBuffer->getPixelFormat()
+ << ", usage 0x" << std::setw(16) << graphicBuffer->getUsage()
+ << std::dec << std::setfill(' ')
+ << ", stride " << graphicBuffer->getStride()
+ << ", generation " << graphicBuffer->getGenerationNumber();
status_t result = igbp->attachBuffer(bqSlot, graphicBuffer);
if (result != OK) {
- ALOGW("attachToBufferQueue -- attachBuffer failed. Error code = %d",
- static_cast<int>(result));
+ LOG(WARNING) << "attachToBufferQueue -- attachBuffer failed: "
+ "status = " << result << ".";
return result;
}
- ALOGV("attachToBufferQueue -- attachBuffer returned slot %d",
- static_cast<int>(*bqSlot));
+ LOG(VERBOSE) << "attachToBufferQueue -- attachBuffer returned slot #"
+ << *bqSlot << ".";
return OK;
}
@@ -1747,11 +1899,11 @@
// If the block's bqId is the same as the desired bqId, just hold.
if ((oldId == bqId) && (oldGeneration == generation)) {
- ALOGV("holdBufferQueueBlock -- import without attaching: "
- "bqId %llu, bqSlot %d, generation %u.",
- static_cast<long long unsigned>(oldId),
- static_cast<int>(oldSlot),
- static_cast<unsigned>(generation));
+ LOG(VERBOSE) << "holdBufferQueueBlock -- import without attaching:"
+ << " bqId " << oldId
+ << ", bqSlot " << oldSlot
+ << ", generation " << generation
+ << ".";
_C2BlockFactory::HoldBlockFromBufferQueue(data, getHgbp(igbp));
return true;
}
@@ -1765,19 +1917,18 @@
status_t result = attachToBufferQueue(block, igbp, generation, &bqSlot);
if (result != OK) {
- ALOGE("holdBufferQueueBlock -- fail to attach: "
- "target bqId %llu, generation %u.",
- static_cast<long long unsigned>(bqId),
- static_cast<unsigned>(generation));
-
+ LOG(ERROR) << "holdBufferQueueBlock -- fail to attach:"
+ << " target bqId " << bqId
+ << ", generation " << generation
+ << ".";
return false;
}
- ALOGV("holdBufferQueueBlock -- attached: "
- "bqId %llu, bqSlot %d, generation %u.",
- static_cast<long long unsigned>(bqId),
- static_cast<int>(bqSlot),
- static_cast<unsigned>(generation));
+ LOG(VERBOSE) << "holdBufferQueueBlock -- attached:"
+ << " bqId " << bqId
+ << ", bqSlot " << bqSlot
+ << ", generation " << generation
+ << ".";
_C2BlockFactory::AssignBlockToBufferQueue(
data, getHgbp(igbp), generation, bqId, bqSlot, true);
return true;
diff --git a/media/codec2/hidl/1.0/vts/OWNERS b/media/codec2/hidl/1.0/vts/OWNERS
new file mode 100644
index 0000000..6733e0c
--- /dev/null
+++ b/media/codec2/hidl/1.0/vts/OWNERS
@@ -0,0 +1,9 @@
+# Media team
+lajos@google.com
+pawin@google.com
+taklee@google.com
+wonsik@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/media/codec2/hidl/1.0/vts/audio/Android.bp b/media/codec2/hidl/1.0/vts/functional/audio/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/audio/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/audio/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioDecTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/audio/VtsHidlC2V1_0TargetAudioEncTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/audio/media_c2_audio_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/audio/media_c2_audio_hidl_test_common.h
similarity index 100%
rename from media/codec2/hidl/1.0/vts/audio/media_c2_audio_hidl_test_common.h
rename to media/codec2/hidl/1.0/vts/functional/audio/media_c2_audio_hidl_test_common.h
diff --git a/media/codec2/hidl/1.0/vts/common/Android.bp b/media/codec2/hidl/1.0/vts/functional/common/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/common/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/common/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/common/README.md b/media/codec2/hidl/1.0/vts/functional/common/README.md
similarity index 100%
rename from media/codec2/hidl/1.0/vts/common/README.md
rename to media/codec2/hidl/1.0/vts/functional/common/README.md
diff --git a/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.cpp b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.cpp
rename to media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
diff --git a/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
similarity index 96%
rename from media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h
rename to media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index a688530..d1557cb 100644
--- a/media/codec2/hidl/1.0/vts/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -94,10 +94,14 @@
(void)buffer;
}
- virtual void onFramesRendered(
- const std::vector<RenderedFrame>& renderedFrames) override {
+ virtual void onFrameRendered(
+ uint64_t bufferQueueId,
+ int32_t slotId,
+ int64_t timestampNs) override {
/* TODO */
- (void)renderedFrames;
+ (void)bufferQueueId;
+ (void)slotId;
+ (void)timestampNs;
}
// std::mutex mQueueLock;
// std::condition_variable mQueueCondition;
diff --git a/media/codec2/hidl/1.0/vts/component/Android.bp b/media/codec2/hidl/1.0/vts/functional/component/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/component/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/component/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/component/VtsHidlC2V1_0TargetComponentTest.cpp b/media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/component/VtsHidlC2V1_0TargetComponentTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/component/VtsHidlC2V1_0TargetComponentTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/master/Android.bp b/media/codec2/hidl/1.0/vts/functional/master/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/master/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/master/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/master/VtsHidlC2V1_0TargetMasterTest.cpp b/media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/master/VtsHidlC2V1_0TargetMasterTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/master/VtsHidlC2V1_0TargetMasterTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_352x288_420p_30fps_32frames.yuv b/media/codec2/hidl/1.0/vts/functional/res/bbb_352x288_420p_30fps_32frames.yuv
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_352x288_420p_30fps_32frames.yuv
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_352x288_420p_30fps_32frames.yuv
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz.aac b/media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz.aac
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz.aac
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz.aac
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_aac_stereo_128kbps_48000hz_multi_frame.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb b/media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz.amrwb
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_amrwb_1ch_14kbps_16000hz_multi_frame.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_av1_176_144.av1 b/media/codec2/hidl/1.0/vts/functional/res/bbb_av1_176_144.av1
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_av1_176_144.av1
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_av1_176_144.av1
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_av1_176_144.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_av1_176_144.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_av1_176_144.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_av1_176_144.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_av1_640_360.av1 b/media/codec2/hidl/1.0/vts/functional/res/bbb_av1_640_360.av1
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_av1_640_360.av1
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_av1_640_360.av1
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_av1_640_360.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_av1_640_360.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_av1_640_360.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_av1_640_360.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_avc_176x144_300kbps_60fps.h264 b/media/codec2/hidl/1.0/vts/functional/res/bbb_avc_176x144_300kbps_60fps.h264
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_avc_176x144_300kbps_60fps.h264
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_avc_176x144_300kbps_60fps.h264
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_avc_176x144_300kbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_avc_176x144_300kbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_avc_176x144_300kbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_avc_176x144_300kbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_avc_640x360_768kbps_30fps.h264 b/media/codec2/hidl/1.0/vts/functional/res/bbb_avc_640x360_768kbps_30fps.h264
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_avc_640x360_768kbps_30fps.h264
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_avc_640x360_768kbps_30fps.h264
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_avc_640x360_768kbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_avc_640x360_768kbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_avc_640x360_768kbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_avc_640x360_768kbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_flac_stereo_680kbps_48000hz.flac b/media/codec2/hidl/1.0/vts/functional/res/bbb_flac_stereo_680kbps_48000hz.flac
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_flac_stereo_680kbps_48000hz.flac
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_flac_stereo_680kbps_48000hz.flac
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_flac_stereo_680kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_flac_stereo_680kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_flac_stereo_680kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_flac_stereo_680kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_g711alaw_1ch_8khz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_g711alaw_1ch_8khz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_g711alaw_1ch_8khz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_g711alaw_1ch_8khz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_g711alaw_1ch_8khz.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_g711alaw_1ch_8khz.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_g711alaw_1ch_8khz.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_g711alaw_1ch_8khz.raw
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_g711mulaw_1ch_8khz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_g711mulaw_1ch_8khz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_g711mulaw_1ch_8khz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_g711mulaw_1ch_8khz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_g711mulaw_1ch_8khz.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_g711mulaw_1ch_8khz.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_g711mulaw_1ch_8khz.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_g711mulaw_1ch_8khz.raw
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_gsm_1ch_8khz_13kbps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_gsm_1ch_8khz_13kbps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_gsm_1ch_8khz_13kbps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_gsm_1ch_8khz_13kbps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_gsm_1ch_8khz_13kbps.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_gsm_1ch_8khz_13kbps.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_gsm_1ch_8khz_13kbps.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_gsm_1ch_8khz_13kbps.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_h263_352x288_300kbps_12fps.h263 b/media/codec2/hidl/1.0/vts/functional/res/bbb_h263_352x288_300kbps_12fps.h263
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_h263_352x288_300kbps_12fps.h263
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_h263_352x288_300kbps_12fps.h263
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_h263_352x288_300kbps_12fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_h263_352x288_300kbps_12fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_h263_352x288_300kbps_12fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_h263_352x288_300kbps_12fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_hevc_176x144_176kbps_60fps.hevc b/media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_176x144_176kbps_60fps.hevc
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_hevc_176x144_176kbps_60fps.hevc
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_176x144_176kbps_60fps.hevc
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_hevc_176x144_176kbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_176x144_176kbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_hevc_176x144_176kbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_176x144_176kbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_hevc_640x360_1600kbps_30fps.hevc b/media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_640x360_1600kbps_30fps.hevc
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_hevc_640x360_1600kbps_30fps.hevc
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_640x360_1600kbps_30fps.hevc
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_hevc_640x360_1600kbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_640x360_1600kbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_hevc_640x360_1600kbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_hevc_640x360_1600kbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz.mp3 b/media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz.mp3
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz.mp3
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz.mp3
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mp3_stereo_192kbps_48000hz_multi_frame.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg2_176x144_105kbps_25fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_176x144_105kbps_25fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg2_176x144_105kbps_25fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_176x144_105kbps_25fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg2_176x144_105kbps_25fps.m2v b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_176x144_105kbps_25fps.m2v
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg2_176x144_105kbps_25fps.m2v
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_176x144_105kbps_25fps.m2v
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg2_352x288_1mbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_352x288_1mbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg2_352x288_1mbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_352x288_1mbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg2_352x288_1mbps_60fps.m2v b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_352x288_1mbps_60fps.m2v
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg2_352x288_1mbps_60fps.m2v
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg2_352x288_1mbps_60fps.m2v
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg4_352x288_512kbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg4_352x288_512kbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg4_352x288_512kbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg4_352x288_512kbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_mpeg4_352x288_512kbps_30fps.m4v b/media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg4_352x288_512kbps_30fps.m4v
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_mpeg4_352x288_512kbps_30fps.m4v
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_mpeg4_352x288_512kbps_30fps.m4v
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_opus_stereo_128kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_opus_stereo_128kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_opus_stereo_128kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_opus_stereo_128kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_opus_stereo_128kbps_48000hz.opus b/media/codec2/hidl/1.0/vts/functional/res/bbb_opus_stereo_128kbps_48000hz.opus
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_opus_stereo_128kbps_48000hz.opus
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_opus_stereo_128kbps_48000hz.opus
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_16khz_s16le.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_16khz_s16le.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_16khz_s16le.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_16khz_s16le.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s16le.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s16le.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s16le.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s16le.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s32le.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s32le.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s32le.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_1ch_8khz_s32le.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_raw_2ch_48khz_s16le.raw b/media/codec2/hidl/1.0/vts/functional/res/bbb_raw_2ch_48khz_s16le.raw
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_raw_2ch_48khz_s16le.raw
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_raw_2ch_48khz_s16le.raw
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vorbis_stereo_128kbps_48000hz.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vorbis_stereo_128kbps_48000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vorbis_stereo_128kbps_48000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vorbis_stereo_128kbps_48000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis b/media/codec2/hidl/1.0/vts/functional/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vorbis_stereo_128kbps_48000hz.vorbis
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp8_176x144_240kbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_176x144_240kbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp8_176x144_240kbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_176x144_240kbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp8_176x144_240kbps_60fps.vp8 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_176x144_240kbps_60fps.vp8
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp8_176x144_240kbps_60fps.vp8
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_176x144_240kbps_60fps.vp8
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp8_640x360_2mbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_640x360_2mbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp8_640x360_2mbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_640x360_2mbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp8_640x360_2mbps_30fps.vp8 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_640x360_2mbps_30fps.vp8
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp8_640x360_2mbps_30fps.vp8
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp8_640x360_2mbps_30fps.vp8
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp9_176x144_285kbps_60fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_176x144_285kbps_60fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp9_176x144_285kbps_60fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_176x144_285kbps_60fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp9_176x144_285kbps_60fps.vp9 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_176x144_285kbps_60fps.vp9
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp9_176x144_285kbps_60fps.vp9
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_176x144_285kbps_60fps.vp9
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp9_640x360_1600kbps_30fps.info b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_640x360_1600kbps_30fps.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp9_640x360_1600kbps_30fps.info
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_640x360_1600kbps_30fps.info
diff --git a/media/codec2/hidl/1.0/vts/res/bbb_vp9_640x360_1600kbps_30fps.vp9 b/media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_640x360_1600kbps_30fps.vp9
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/bbb_vp9_640x360_1600kbps_30fps.vp9
rename to media/codec2/hidl/1.0/vts/functional/res/bbb_vp9_640x360_1600kbps_30fps.vp9
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz.amrnb b/media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz.amrnb
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz.amrnb
rename to media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz.amrnb
Binary files differ
diff --git a/media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz.info b/media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz.info
rename to media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz.info
diff --git a/media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info b/media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info
similarity index 100%
rename from media/codec2/hidl/1.0/vts/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info
rename to media/codec2/hidl/1.0/vts/functional/res/sine_amrnb_1ch_12kbps_8000hz_multi_frame.info
diff --git a/media/codec2/hidl/1.0/vts/video/Android.bp b/media/codec2/hidl/1.0/vts/functional/video/Android.bp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/video/Android.bp
rename to media/codec2/hidl/1.0/vts/functional/video/Android.bp
diff --git a/media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoDecTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoEncTest.cpp b/media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
similarity index 100%
rename from media/codec2/hidl/1.0/vts/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
rename to media/codec2/hidl/1.0/vts/functional/video/VtsHidlC2V1_0TargetVideoEncTest.cpp
diff --git a/media/codec2/hidl/1.0/vts/video/media_c2_video_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
similarity index 100%
rename from media/codec2/hidl/1.0/vts/video/media_c2_video_hidl_test_common.h
rename to media/codec2/hidl/1.0/vts/functional/video/media_c2_video_hidl_test_common.h
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index cd374b0..5b52fcd 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,7 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Codec2Client"
-#include <log/log.h>
+#include <android-base/logging.h>
#include <codec2/hidl/client.h>
@@ -32,7 +32,6 @@
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <hidl/HidlSupport.h>
#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>
-#undef LOG
#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
#include <android/hardware/media/c2/1.0/IComponent.h>
@@ -99,19 +98,17 @@
return mName;
}
-Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const {
- return static_cast<Base*>(mBase.get());
-}
-
Codec2ConfigurableClient::Codec2ConfigurableClient(
- const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) {
- Return<void> transStatus = base->getName(
- [this](const hidl_string& name) {
- mName = name.c_str();
- });
- if (!transStatus.isOk()) {
- ALOGE("Cannot obtain name from IConfigurable.");
- }
+ const sp<IConfigurable>& base)
+ : mBase{base},
+ mName{[base]() -> C2String {
+ C2String outName;
+ Return<void> transStatus = base->getName(
+ [&outName](const hidl_string& name) {
+ outName = name.c_str();
+ });
+ return transStatus.isOk() ? outName : "";
+ }()} {
}
c2_status_t Codec2ConfigurableClient::query(
@@ -124,7 +121,7 @@
size_t numIndices = 0;
for (C2Param* const& stackParam : stackParams) {
if (!stackParam) {
- ALOGW("query -- null stack param encountered.");
+ LOG(WARNING) << "query -- null stack param encountered.";
continue;
}
indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
@@ -139,32 +136,31 @@
heapParams->reserve(heapParams->size() + numIndices);
}
c2_status_t status;
- Return<void> transStatus = base()->query(
+ Return<void> transStatus = mBase->query(
indices,
mayBlock == C2_MAY_BLOCK,
[&status, &numStackIndices, &stackParams, heapParams](
Status s, const Params& p) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK && status != C2_BAD_INDEX) {
- ALOGE("query -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "query -- call failed: "
+ << status << ".";
return;
}
std::vector<C2Param*> paramPointers;
- c2_status_t parseStatus = parseParamsBlob(¶mPointers, p);
- if (parseStatus != C2_OK) {
- ALOGE("query -- error while parsing params. "
- "Error code = %d", static_cast<int>(status));
- status = parseStatus;
+ if (!parseParamsBlob(¶mPointers, p)) {
+ LOG(ERROR) << "query -- error while parsing params.";
+ status = C2_CORRUPTED;
return;
}
size_t i = 0;
- for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
+ for (auto it = paramPointers.begin();
+ it != paramPointers.end(); ) {
C2Param* paramPointer = *it;
if (numStackIndices > 0) {
--numStackIndices;
if (!paramPointer) {
- ALOGW("query -- null stack param.");
+ LOG(WARNING) << "query -- null stack param.";
++it;
continue;
}
@@ -172,37 +168,41 @@
++i;
}
if (i >= stackParams.size()) {
- ALOGE("query -- unexpected error.");
+ LOG(ERROR) << "query -- unexpected error.";
status = C2_CORRUPTED;
return;
}
if (stackParams[i]->index() != paramPointer->index()) {
- ALOGW("query -- param skipped. index = %d",
- static_cast<int>(stackParams[i]->index()));
+ LOG(WARNING) << "query -- param skipped: "
+ "index = "
+ << stackParams[i]->index() << ".";
stackParams[i++]->invalidate();
continue;
}
if (!stackParams[i++]->updateFrom(*paramPointer)) {
- ALOGW("query -- param update failed. index = %d",
- static_cast<int>(paramPointer->index()));
+ LOG(WARNING) << "query -- param update failed: "
+ "index = "
+ << paramPointer->index() << ".";
}
} else {
if (!paramPointer) {
- ALOGW("query -- null heap param.");
+ LOG(WARNING) << "query -- null heap param.";
++it;
continue;
}
if (!heapParams) {
- ALOGW("query -- unexpected extra stack param.");
+ LOG(WARNING) << "query -- "
+ "unexpected extra stack param.";
} else {
- heapParams->emplace_back(C2Param::Copy(*paramPointer));
+ heapParams->emplace_back(
+ C2Param::Copy(*paramPointer));
}
}
++it;
}
});
if (!transStatus.isOk()) {
- ALOGE("query -- transaction failed.");
+ LOG(ERROR) << "query -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
return status;
@@ -213,13 +213,12 @@
c2_blocking_t mayBlock,
std::vector<std::unique_ptr<C2SettingResult>>* const failures) {
Params hidlParams;
- Status hidlStatus = createParamsBlob(&hidlParams, params);
- if (hidlStatus != Status::OK) {
- ALOGE("config -- bad input.");
+ if (!createParamsBlob(&hidlParams, params)) {
+ LOG(ERROR) << "config -- bad input.";
return C2_TRANSACTION_FAILED;
}
c2_status_t status;
- Return<void> transStatus = base()->config(
+ Return<void> transStatus = mBase->config(
hidlParams,
mayBlock == C2_MAY_BLOCK,
[&status, ¶ms, failures](
@@ -227,24 +226,27 @@
const hidl_vec<SettingResult> f,
const Params& o) {
status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- ALOGD("config -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ if (status != C2_OK && status != C2_BAD_INDEX) {
+ LOG(DEBUG) << "config -- call failed: "
+ << status << ".";
}
size_t i = failures->size();
failures->resize(i + f.size());
for (const SettingResult& sf : f) {
- status = objcpy(&(*failures)[i++], sf);
- if (status != C2_OK) {
- ALOGE("config -- invalid returned SettingResult. "
- "Error code = %d", static_cast<int>(status));
+ if (!objcpy(&(*failures)[i++], sf)) {
+ LOG(ERROR) << "config -- "
+ << "invalid SettingResult returned.";
return;
}
}
- status = updateParamsFromBlob(params, o);
+ if (!updateParamsFromBlob(params, o)) {
+ LOG(ERROR) << "config -- "
+ << "failed to parse returned params.";
+ status = C2_CORRUPTED;
+ }
});
if (!transStatus.isOk()) {
- ALOGE("config -- transaction failed.");
+ LOG(ERROR) << "config -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
return status;
@@ -254,7 +256,7 @@
std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const {
// TODO: Cache and query properly!
c2_status_t status;
- Return<void> transStatus = base()->querySupportedParams(
+ Return<void> transStatus = mBase->querySupportedParams(
std::numeric_limits<uint32_t>::min(),
std::numeric_limits<uint32_t>::max(),
[&status, params](
@@ -262,24 +264,22 @@
const hidl_vec<ParamDescriptor>& p) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
- ALOGE("querySupportedParams -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "querySupportedParams -- call failed: "
+ << status << ".";
return;
}
size_t i = params->size();
params->resize(i + p.size());
for (const ParamDescriptor& sp : p) {
- status = objcpy(&(*params)[i++], sp);
- if (status != C2_OK) {
- ALOGE("querySupportedParams -- "
- "invalid returned ParamDescriptor. "
- "Error code = %d", static_cast<int>(status));
+ if (!objcpy(&(*params)[i++], sp)) {
+ LOG(ERROR) << "querySupportedParams -- "
+ << "invalid returned ParamDescriptor.";
return;
}
}
});
if (!transStatus.isOk()) {
- ALOGE("querySupportedParams -- transaction failed.");
+ LOG(ERROR) << "querySupportedParams -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
return status;
@@ -290,15 +290,14 @@
c2_blocking_t mayBlock) const {
hidl_vec<FieldSupportedValuesQuery> inFields(fields.size());
for (size_t i = 0; i < fields.size(); ++i) {
- Status hidlStatus = objcpy(&inFields[i], fields[i]);
- if (hidlStatus != Status::OK) {
- ALOGE("querySupportedValues -- bad input");
+ if (!objcpy(&inFields[i], fields[i])) {
+ LOG(ERROR) << "querySupportedValues -- bad input";
return C2_TRANSACTION_FAILED;
}
}
c2_status_t status;
- Return<void> transStatus = base()->querySupportedValues(
+ Return<void> transStatus = mBase->querySupportedValues(
inFields,
mayBlock == C2_MAY_BLOCK,
[&status, &inFields, &fields](
@@ -306,27 +305,28 @@
const hidl_vec<FieldSupportedValuesQueryResult>& r) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
- ALOGE("querySupportedValues -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "querySupportedValues -- call failed: "
+ << status << ".";
return;
}
if (r.size() != fields.size()) {
- ALOGE("querySupportedValues -- input and output lists "
- "have different sizes.");
+ LOG(ERROR) << "querySupportedValues -- "
+ "input and output lists "
+ "have different sizes.";
status = C2_CORRUPTED;
return;
}
for (size_t i = 0; i < fields.size(); ++i) {
- status = objcpy(&fields[i], inFields[i], r[i]);
- if (status != C2_OK) {
- ALOGE("querySupportedValues -- invalid returned value. "
- "Error code = %d", static_cast<int>(status));
+ if (!objcpy(&fields[i], inFields[i], r[i])) {
+ LOG(ERROR) << "querySupportedValues -- "
+ "invalid returned value.";
+ status = C2_CORRUPTED;
return;
}
}
});
if (!transStatus.isOk()) {
- ALOGE("querySupportedValues -- transaction failed.");
+ LOG(ERROR) << "querySupportedValues -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
return status;
@@ -339,22 +339,24 @@
virtual Return<void> onWorkDone(const WorkBundle& workBundle) override {
std::list<std::unique_ptr<C2Work>> workItems;
- c2_status_t status = objcpy(&workItems, workBundle);
- if (status != C2_OK) {
- ALOGI("onWorkDone -- received corrupted WorkBundle. "
- "status = %d.", static_cast<int>(status));
+ if (!objcpy(&workItems, workBundle)) {
+ LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
return Void();
}
// release input buffers potentially held by the component from queue
size_t numDiscardedInputBuffers = 0;
- std::shared_ptr<Codec2Client::Component> strongComponent = component.lock();
+ std::shared_ptr<Codec2Client::Component> strongComponent =
+ component.lock();
if (strongComponent) {
- numDiscardedInputBuffers = strongComponent->handleOnWorkDone(workItems);
+ numDiscardedInputBuffers =
+ strongComponent->handleOnWorkDone(workItems);
}
if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
- listener->onWorkDone(component, workItems, numDiscardedInputBuffers);
+ listener->onWorkDone(component,
+ workItems,
+ numDiscardedInputBuffers);
} else {
- ALOGD("onWorkDone -- listener died.");
+ LOG(DEBUG) << "onWorkDone -- listener died.";
}
return Void();
}
@@ -363,13 +365,10 @@
const hidl_vec<SettingResult>& settingResults) override {
std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
settingResults.size());
- c2_status_t status;
for (size_t i = 0; i < settingResults.size(); ++i) {
std::unique_ptr<C2SettingResult> c2SettingResult;
- status = objcpy(&c2SettingResult, settingResults[i]);
- if (status != C2_OK) {
- ALOGI("onTripped -- received corrupted SettingResult. "
- "status = %d.", static_cast<int>(status));
+ if (!objcpy(&c2SettingResult, settingResults[i])) {
+ LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
return Void();
}
c2SettingResults[i] = std::move(c2SettingResult);
@@ -377,20 +376,21 @@
if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
listener->onTripped(component, c2SettingResults);
} else {
- ALOGD("onTripped -- listener died.");
+ LOG(DEBUG) << "onTripped -- listener died.";
}
return Void();
}
virtual Return<void> onError(Status s, uint32_t errorCode) override {
- ALOGD("onError -- status = %d, errorCode = %u.",
- static_cast<int>(s),
- static_cast<unsigned>(errorCode));
+ LOG(DEBUG) << "onError --"
+ << " status = " << s
+ << ", errorCode = " << errorCode
+ << ".";
if (std::shared_ptr<Listener> listener = base.lock()) {
listener->onError(component, s == Status::OK ?
errorCode : static_cast<c2_status_t>(s));
} else {
- ALOGD("onError -- listener died.");
+ LOG(DEBUG) << "onError -- listener died.";
}
return Void();
}
@@ -398,55 +398,70 @@
virtual Return<void> onFramesRendered(
const hidl_vec<RenderedFrame>& renderedFrames) override {
std::shared_ptr<Listener> listener = base.lock();
- std::vector<Codec2Client::Listener::RenderedFrame> rfs;
- rfs.reserve(renderedFrames.size());
- for (const RenderedFrame& rf : renderedFrames) {
- if (rf.slotId >= 0) {
- if (listener) {
- rfs.emplace_back(rf.bufferQueueId,
- rf.slotId,
- rf.timestampNs);
- }
- } else {
- std::shared_ptr<Codec2Client::Component> strongComponent =
- component.lock();
- if (strongComponent) {
- uint64_t frameIndex = rf.bufferQueueId;
- size_t bufferIndex = static_cast<size_t>(~rf.slotId);
- ALOGV("Received death notification of input buffer: "
- "frameIndex = %llu, bufferIndex = %zu.",
- static_cast<long long unsigned>(frameIndex),
- bufferIndex);
- std::shared_ptr<C2Buffer> buffer =
- strongComponent->freeInputBuffer(
- frameIndex, bufferIndex);
- if (buffer) {
- listener->onInputBufferDone(buffer);
- }
- }
- }
+ if (!listener) {
+ LOG(DEBUG) << "onFramesRendered -- listener died.";
+ return Void();
}
- if (!rfs.empty()) {
- if (listener) {
- listener->onFramesRendered(rfs);
- } else {
- ALOGD("onFramesRendered -- listener died.");
+ for (const RenderedFrame& renderedFrame : renderedFrames) {
+ listener->onFrameRendered(
+ renderedFrame.bufferQueueId,
+ renderedFrame.slotId,
+ renderedFrame.timestampNs);
+ }
+ return Void();
+ }
+
+ virtual Return<void> onInputBuffersReleased(
+ const hidl_vec<InputBuffer>& inputBuffers) override {
+ std::shared_ptr<Listener> listener = base.lock();
+ if (!listener) {
+ LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
+ return Void();
+ }
+ std::shared_ptr<Codec2Client::Component> strongComponent =
+ component.lock();
+ if (!strongComponent) {
+ LOG(DEBUG) << "onInputBuffersReleased -- component died.";
+ return Void();
+ }
+ for (const InputBuffer& inputBuffer : inputBuffers) {
+ std::shared_ptr<C2Buffer> buffer =
+ strongComponent->freeInputBuffer(
+ inputBuffer.frameIndex,
+ inputBuffer.arrayIndex);
+ LOG(VERBOSE) << "onInputBuffersReleased --"
+ " received death notification of"
+ " input buffer:"
+ " frameIndex = " << inputBuffer.frameIndex
+ << ", bufferIndex = " << inputBuffer.arrayIndex
+ << ".";
+ if (buffer) {
+ listener->onInputBufferDone(buffer);
}
}
return Void();
}
+
};
// Codec2Client
-Codec2Client::Base* Codec2Client::base() const {
- return static_cast<Base*>(mBase.get());
-}
-
-Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base, std::string instanceName) :
- Codec2ConfigurableClient(base), mListed(false), mInstanceName(instanceName) {
+Codec2Client::Codec2Client(const sp<IComponentStore>& base,
+ std::string serviceName)
+ : Configurable{
+ [base]() -> sp<IConfigurable> {
+ Return<sp<IConfigurable>> transResult =
+ base->getConfigurable();
+ return transResult.isOk() ?
+ static_cast<sp<IConfigurable>>(transResult) :
+ nullptr;
+ }()
+ },
+ mBase{base},
+ mListed{false},
+ mServiceName{serviceName} {
Return<sp<IClientManager>> transResult = base->getPoolClientManager();
if (!transResult.isOk()) {
- ALOGE("getPoolClientManager -- failed transaction.");
+ LOG(ERROR) << "getPoolClientManager -- transaction failed.";
} else {
mHostPoolManager = static_cast<sp<IClientManager>>(transResult);
}
@@ -457,13 +472,10 @@
const std::shared_ptr<Codec2Client::Listener>& listener,
std::shared_ptr<Codec2Client::Component>* const component) {
- // TODO: Add support for Bufferpool
-
-
c2_status_t status;
- sp<Component::HidlListener> hidlListener = new Component::HidlListener();
+ sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
hidlListener->base = listener;
- Return<void> transStatus = base()->createComponent(
+ Return<void> transStatus = mBase->createComponent(
name,
hidlListener,
ClientManager::getInstance(),
@@ -478,23 +490,24 @@
hidlListener->component = *component;
});
if (!transStatus.isOk()) {
- ALOGE("createComponent -- failed transaction.");
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- transaction failed.";
return C2_TRANSACTION_FAILED;
- }
-
- if (status != C2_OK) {
+ } else if (status != C2_OK) {
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- call failed: " << status << ".";
return status;
- }
-
- if (!*component) {
- ALOGE("createComponent -- null component.");
+ } else if (!*component) {
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- null component.";
return C2_CORRUPTED;
}
status = (*component)->setDeathListener(*component, listener);
if (status != C2_OK) {
- ALOGE("createComponent -- setDeathListener returned error: %d.",
- static_cast<int>(status));
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- failed to set up death listener: "
+ << status << ".";
}
(*component)->mBufferPoolSender.setReceiver(mHostPoolManager);
@@ -505,44 +518,51 @@
const C2String& name,
std::shared_ptr<Codec2Client::Interface>* const interface) {
c2_status_t status;
- Return<void> transStatus = base()->createInterface(
+ Return<void> transStatus = mBase->createInterface(
name,
[&status, interface](
Status s,
const sp<IComponentInterface>& i) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
- ALOGE("createInterface -- call failed. "
- "Error code = %d", static_cast<int>(status));
return;
}
- *interface = std::make_shared<Codec2Client::Interface>(i);
+ *interface = std::make_shared<Interface>(i);
});
if (!transStatus.isOk()) {
- ALOGE("createInterface -- failed transaction.");
+ LOG(ERROR) << "createInterface(" << name.c_str()
+ << ") -- transaction failed.";
return C2_TRANSACTION_FAILED;
+ } else if (status != C2_OK) {
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- call failed: " << status << ".";
+ return status;
}
+
return status;
}
c2_status_t Codec2Client::createInputSurface(
- std::shared_ptr<Codec2Client::InputSurface>* const inputSurface) {
- Return<sp<IInputSurface>> transResult = base()->createInputSurface();
- if (!transResult.isOk()) {
- ALOGE("createInputSurface -- failed transaction.");
+ std::shared_ptr<InputSurface>* const inputSurface) {
+ c2_status_t status;
+ Return<void> transStatus = mBase->createInputSurface(
+ [&status, inputSurface](
+ Status s,
+ const sp<IInputSurface>& i) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ return;
+ }
+ *inputSurface = std::make_shared<InputSurface>(i);
+ });
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "createInputSurface -- transaction failed.";
return C2_TRANSACTION_FAILED;
+ } else if (status != C2_OK) {
+ LOG(DEBUG) << "createInputSurface -- call failed: "
+ << status << ".";
}
- sp<IInputSurface> result = static_cast<sp<IInputSurface>>(transResult);
- if (!result) {
- *inputSurface = nullptr;
- return C2_OK;
- }
- *inputSurface = std::make_shared<InputSurface>(result);
- if (!*inputSurface) {
- ALOGE("createInputSurface -- unknown error.");
- return C2_CORRUPTED;
- }
- return C2_OK;
+ return status;
}
const std::vector<C2Component::Traits>& Codec2Client::listComponents() const {
@@ -550,22 +570,26 @@
if (mListed) {
return mTraitsList;
}
- Return<void> transStatus = base()->listComponents(
- [this](const hidl_vec<IComponentStore::ComponentTraits>& t) {
+ Return<void> transStatus = mBase->listComponents(
+ [this](Status s,
+ const hidl_vec<IComponentStore::ComponentTraits>& t) {
+ if (s != Status::OK) {
+ LOG(DEBUG) << "listComponents -- call failed: "
+ << static_cast<c2_status_t>(s) << ".";
+ return;
+ }
mTraitsList.resize(t.size());
mAliasesBuffer.resize(t.size());
for (size_t i = 0; i < t.size(); ++i) {
- c2_status_t status = objcpy(
- &mTraitsList[i], &mAliasesBuffer[i], t[i]);
- mTraitsList[i].owner = mInstanceName;
- if (status != C2_OK) {
- ALOGE("listComponents -- corrupted output.");
+ if (!objcpy(&mTraitsList[i], &mAliasesBuffer[i], t[i])) {
+ LOG(ERROR) << "listComponents -- corrupted output.";
return;
}
+ mTraitsList[i].owner = mServiceName;
}
});
if (!transStatus.isOk()) {
- ALOGE("listComponents -- failed transaction.");
+ LOG(ERROR) << "listComponents -- transaction failed.";
}
mListed = true;
return mTraitsList;
@@ -577,7 +601,7 @@
// TODO: Implement?
(void)src;
(void)dst;
- ALOGE("copyBuffer not implemented");
+ LOG(ERROR) << "copyBuffer not implemented";
return C2_OMITTED;
}
@@ -597,21 +621,25 @@
const hidl_vec<StructDescriptor>& sd) {
c2_status_t status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
- ALOGE("getStructDescriptors -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "SimpleParamReflector -- "
+ "getStructDescriptors() failed: "
+ << status << ".";
descriptor.reset();
return;
}
if (sd.size() != 1) {
- ALOGD("getStructDescriptors -- returned vector of size %zu.",
- sd.size());
+ LOG(DEBUG) << "SimpleParamReflector -- "
+ "getStructDescriptors() "
+ "returned vector of size "
+ << sd.size() << ". "
+ "It should be 1.";
descriptor.reset();
return;
}
- status = objcpy(&descriptor, sd[0]);
- if (status != C2_OK) {
- ALOGD("getStructDescriptors -- failed to convert. "
- "Error code = %d", static_cast<int>(status));
+ if (!objcpy(&descriptor, sd[0])) {
+ LOG(DEBUG) << "SimpleParamReflector -- "
+ "getStructDescriptors() returned "
+ "corrupted data.";
descriptor.reset();
return;
}
@@ -625,44 +653,44 @@
sp<Base> mBase;
};
- return std::make_shared<SimpleParamReflector>(base());
+ return std::make_shared<SimpleParamReflector>(mBase);
};
std::shared_ptr<Codec2Client> Codec2Client::CreateFromService(
- const char* instanceName, bool waitForService) {
- if (!instanceName) {
+ const char* serviceName, bool waitForService) {
+ if (!serviceName) {
return nullptr;
}
sp<Base> baseStore = waitForService ?
- Base::getService(instanceName) :
- Base::tryGetService(instanceName);
+ Base::getService(serviceName) :
+ Base::tryGetService(serviceName);
if (!baseStore) {
if (waitForService) {
- ALOGW("Codec2.0 service \"%s\" inaccessible. "
- "Check the device manifest.",
- instanceName);
+ LOG(WARNING) << "Codec2.0 service \"" << serviceName << "\""
+ " inaccessible. Check the device manifest.";
} else {
- ALOGD("Codec2.0 service \"%s\" unavailable right now. "
- "Try again later.",
- instanceName);
+ LOG(DEBUG) << "Codec2.0 service \"" << serviceName << "\""
+ " unavailable at the moment. "
+ " Wait or check the device manifest.";
}
return nullptr;
}
- return std::make_shared<Codec2Client>(baseStore, instanceName);
+ return std::make_shared<Codec2Client>(baseStore, serviceName);
}
c2_status_t Codec2Client::ForAllStores(
const std::string &key,
- std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate) {
+ std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)>
+ predicate) {
c2_status_t status = C2_NO_INIT; // no IComponentStores present
// Cache the mapping key -> index of Codec2Client in getClient().
static std::mutex key2IndexMutex;
static std::map<std::string, size_t> key2Index;
- // By default try all stores. However, try the last known client first. If the last known
- // client fails, retry once. We do this by pushing the last known client in front of the
- // list of all clients.
+ // By default try all stores. However, try the last known client first. If
+ // the last known client fails, retry once. We do this by pushing the last
+ // known client in front of the list of all clients.
std::deque<size_t> indices;
for (size_t index = kNumClients; index > 0; ) {
indices.push_front(--index);
@@ -688,7 +716,8 @@
}
}
if (wasMapped) {
- ALOGI("Could not find '%s' in last instance. Retrying...", key.c_str());
+ LOG(INFO) << "Could not find \"" << key << "\""
+ " in the last instance. Retrying...";
wasMapped = false;
}
}
@@ -704,20 +733,27 @@
c2_status_t status = ForAllStores(
componentName,
[owner, &component, componentName, &listener](
- const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
- c2_status_t status = client->createComponent(componentName, listener, &component);
+ const std::shared_ptr<Codec2Client> &client)
+ -> c2_status_t {
+ c2_status_t status = client->createComponent(componentName,
+ listener,
+ &component);
if (status == C2_OK) {
if (owner) {
*owner = client;
}
} else if (status != C2_NOT_FOUND) {
- ALOGD("IComponentStore(%s)::createComponent('%s') returned %s",
- client->getInstanceName().c_str(), componentName, asString(status));
+ LOG(DEBUG) << "IComponentStore("
+ << client->getServiceName()
+ << ")::createComponent(\"" << componentName
+ << "\") returned status = "
+ << status << ".";
}
return status;
});
if (status != C2_OK) {
- ALOGI("Could not create component '%s' (%s)", componentName, asString(status));
+ LOG(DEBUG) << "Could not create component \"" << componentName << "\". "
+ "Status = " << status << ".";
}
return component;
}
@@ -730,20 +766,26 @@
c2_status_t status = ForAllStores(
interfaceName,
[owner, &interface, interfaceName](
- const std::shared_ptr<Codec2Client> &client) -> c2_status_t {
- c2_status_t status = client->createInterface(interfaceName, &interface);
+ const std::shared_ptr<Codec2Client> &client)
+ -> c2_status_t {
+ c2_status_t status = client->createInterface(interfaceName,
+ &interface);
if (status == C2_OK) {
if (owner) {
*owner = client;
}
} else if (status != C2_NOT_FOUND) {
- ALOGD("IComponentStore(%s)::createInterface('%s') returned %s",
- client->getInstanceName().c_str(), interfaceName, asString(status));
+ LOG(DEBUG) << "IComponentStore("
+ << client->getServiceName()
+ << ")::createInterface(\"" << interfaceName
+ << "\") returned status = "
+ << status << ".";
}
return status;
});
if (status != C2_OK) {
- ALOGI("Could not create interface '%s' (%s)", interfaceName, asString(status));
+ LOG(DEBUG) << "Could not create interface \"" << interfaceName << "\". "
+ "Status = " << status << ".";
}
return interface;
}
@@ -762,7 +804,8 @@
}
}
}
- ALOGW("Could not create an input surface from any Codec2.0 services.");
+ LOG(INFO) << "Could not create an input surface "
+ "from any Codec2.0 services.";
return nullptr;
}
@@ -798,15 +841,39 @@
Codec2Client::Listener::~Listener() {
}
-// Codec2Client::Component
-
-Codec2Client::Component::Base* Codec2Client::Component::base() const {
- return static_cast<Base*>(mBase.get());
+// Codec2Client::Interface
+Codec2Client::Interface::Interface(const sp<Base>& base)
+ : Configurable{
+ [base]() -> sp<IConfigurable> {
+ Return<sp<IConfigurable>> transResult =
+ base->getConfigurable();
+ return transResult.isOk() ?
+ static_cast<sp<IConfigurable>>(transResult) :
+ nullptr;
+ }()
+ },
+ mBase{base} {
}
-Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) :
- Codec2Client::Configurable(base),
- mBufferPoolSender(nullptr) {
+// Codec2Client::Component
+Codec2Client::Component::Component(const sp<Base>& base)
+ : Configurable{
+ [base]() -> sp<IConfigurable> {
+ Return<sp<IComponentInterface>> transResult1 =
+ base->getInterface();
+ if (!transResult1.isOk()) {
+ return nullptr;
+ }
+ Return<sp<IConfigurable>> transResult2 =
+ static_cast<sp<IComponentInterface>>(transResult1)->
+ getConfigurable();
+ return transResult2.isOk() ?
+ static_cast<sp<IConfigurable>>(transResult2) :
+ nullptr;
+ }()
+ },
+ mBase{base},
+ mBufferPoolSender{nullptr} {
}
Codec2Client::Component::~Component() {
@@ -817,7 +884,7 @@
C2BlockPool::local_id_t* blockPoolId,
std::shared_ptr<Codec2Client::Configurable>* configurable) {
c2_status_t status;
- Return<void> transStatus = base()->createBlockPool(
+ Return<void> transStatus = mBase->createBlockPool(
static_cast<uint32_t>(id),
[&status, blockPoolId, configurable](
Status s,
@@ -826,15 +893,15 @@
status = static_cast<c2_status_t>(s);
configurable->reset();
if (status != C2_OK) {
- ALOGE("createBlockPool -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "createBlockPool -- call failed: "
+ << status << ".";
return;
}
*blockPoolId = static_cast<C2BlockPool::local_id_t>(pId);
- *configurable = std::make_shared<Codec2Client::Configurable>(c);
+ *configurable = std::make_shared<Configurable>(c);
});
if (!transStatus.isOk()) {
- ALOGE("createBlockPool -- transaction failed.");
+ LOG(ERROR) << "createBlockPool -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
return status;
@@ -842,10 +909,10 @@
c2_status_t Codec2Client::Component::destroyBlockPool(
C2BlockPool::local_id_t localId) {
- Return<Status> transResult = base()->destroyBlockPool(
+ Return<Status> transResult = mBase->destroyBlockPool(
static_cast<uint64_t>(localId));
if (!transResult.isOk()) {
- ALOGE("destroyBlockPool -- transaction failed.");
+ LOG(ERROR) << "destroyBlockPool -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
return static_cast<c2_status_t>(static_cast<Status>(transResult));
@@ -859,7 +926,8 @@
if (work) {
if (work->worklets.empty()
|| !work->worklets.back()
- || (work->worklets.back()->output.flags & C2FrameData::FLAG_INCOMPLETE) == 0) {
+ || (work->worklets.back()->output.flags &
+ C2FrameData::FLAG_INCOMPLETE) == 0) {
// input is complete
inputDone.emplace_back(work->input.ordinal.frameIndex.peeku());
}
@@ -872,13 +940,14 @@
for (uint64_t inputIndex : inputDone) {
auto it = mInputBuffers.find(inputIndex);
if (it == mInputBuffers.end()) {
- ALOGV("onWorkDone -- returned consumed/unknown "
- "input frame: index %llu",
- (long long)inputIndex);
+ LOG(VERBOSE) << "onWorkDone -- returned consumed/unknown "
+ "input frame: index = "
+ << inputIndex << ".";
} else {
- ALOGV("onWorkDone -- processed input frame: "
- "index %llu (containing %zu buffers)",
- (long long)inputIndex, it->second.size());
+ LOG(VERBOSE) << "onWorkDone -- processed input frame: "
+ << inputIndex
+ << " (containing " << it->second.size()
+ << " buffers).";
mInputBuffers.erase(it);
mInputBufferCount.erase(inputIndex);
++numDiscardedInputBuffers;
@@ -906,21 +975,21 @@
std::lock_guard<std::mutex> lock(mInputBuffersMutex);
auto it = mInputBuffers.find(frameIndex);
if (it == mInputBuffers.end()) {
- ALOGI("freeInputBuffer -- Unrecognized input frame index %llu.",
- static_cast<long long unsigned>(frameIndex));
+ LOG(INFO) << "freeInputBuffer -- Unrecognized input frame index "
+ << frameIndex << ".";
return nullptr;
}
if (bufferIndex >= it->second.size()) {
- ALOGI("freeInputBuffer -- Input buffer no. %zu is invalid in "
- "input frame index %llu.",
- bufferIndex, static_cast<long long unsigned>(frameIndex));
+ LOG(INFO) << "freeInputBuffer -- Input buffer number " << bufferIndex
+ << " is not valid in input with frame index " << frameIndex
+ << ".";
return nullptr;
}
buffer = it->second[bufferIndex];
if (!buffer) {
- ALOGI("freeInputBuffer -- Input buffer no. %zu in "
- "input frame index %llu has already been freed.",
- bufferIndex, static_cast<long long unsigned>(frameIndex));
+ LOG(INFO) << "freeInputBuffer -- Input buffer number " << bufferIndex
+ << " in input with frame index " << frameIndex
+ << " has already been freed.";
return nullptr;
}
it->second[bufferIndex] = nullptr;
@@ -949,33 +1018,33 @@
if (!res.second) {
// TODO: append? - for now we are replacing
res.first->second = work->input.buffers;
- ALOGI("queue -- duplicate input frame: index %llu. "
- "Discarding the old input frame...",
- (long long)inputIndex);
+ LOG(INFO) << "queue -- duplicate input frame index: "
+ << inputIndex
+ << ". Discarding the old input frame...";
}
mInputBufferCount[inputIndex] = work->input.buffers.size();
- ALOGV("queue -- queueing input frame: "
- "index %llu (containing %zu buffers)",
- (long long)inputIndex, work->input.buffers.size());
+ LOG(VERBOSE) << "queue -- queuing input frame: "
+ << "index = " << inputIndex
+ << ", number of buffers = "
+ << work->input.buffers.size()
+ << ".";
}
}
WorkBundle workBundle;
- Status hidlStatus = objcpy(&workBundle, *items, &mBufferPoolSender);
- if (hidlStatus != Status::OK) {
- ALOGE("queue -- bad input.");
+ if (!objcpy(&workBundle, *items, &mBufferPoolSender)) {
+ LOG(ERROR) << "queue -- bad input.";
return C2_TRANSACTION_FAILED;
}
- Return<Status> transStatus = base()->queue(workBundle);
+ Return<Status> transStatus = mBase->queue(workBundle);
if (!transStatus.isOk()) {
- ALOGE("queue -- transaction failed.");
+ LOG(ERROR) << "queue -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
c2_status_t status =
static_cast<c2_status_t>(static_cast<Status>(transStatus));
if (status != C2_OK) {
- ALOGE("queue -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "queue -- call failed: " << status << ".";
}
return status;
}
@@ -985,19 +1054,22 @@
std::list<std::unique_ptr<C2Work>>* const flushedWork) {
(void)mode; // Flush mode isn't supported in HIDL yet.
c2_status_t status;
- Return<void> transStatus = base()->flush(
+ Return<void> transStatus = mBase->flush(
[&status, flushedWork](
Status s, const WorkBundle& wb) {
status = static_cast<c2_status_t>(s);
if (status != C2_OK) {
- ALOGE("flush -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "flush -- call failed: " << status << ".";
return;
}
- status = objcpy(flushedWork, wb);
+ if (!objcpy(flushedWork, wb)) {
+ status = C2_CORRUPTED;
+ } else {
+ status = C2_OK;
+ }
});
if (!transStatus.isOk()) {
- ALOGE("flush -- transaction failed.");
+ LOG(ERROR) << "flush -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
@@ -1021,13 +1093,14 @@
std::lock_guard<std::mutex> lock(mInputBuffersMutex);
auto it = mInputBuffers.find(flushedIndex);
if (it == mInputBuffers.end()) {
- ALOGV("flush -- returned consumed/unknown input frame: "
- "index %llu",
- (long long)flushedIndex);
+ LOG(VERBOSE) << "flush -- returned consumed/unknown input frame: "
+ "index = " << flushedIndex << ".";
} else {
- ALOGV("flush -- returned unprocessed input frame: "
- "index %llu (containing %zu buffers)",
- (long long)flushedIndex, mInputBufferCount[flushedIndex]);
+ LOG(VERBOSE) << "flush -- returned unprocessed input frame: "
+ "index = " << flushedIndex
+ << ", number of buffers = "
+ << mInputBufferCount[flushedIndex]
+ << ".";
mInputBuffers.erase(it);
mInputBufferCount.erase(flushedIndex);
}
@@ -1048,47 +1121,44 @@
}
c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
- Return<Status> transStatus = base()->drain(
+ Return<Status> transStatus = mBase->drain(
mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
if (!transStatus.isOk()) {
- ALOGE("drain -- transaction failed.");
+ LOG(ERROR) << "drain -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
c2_status_t status =
static_cast<c2_status_t>(static_cast<Status>(transStatus));
if (status != C2_OK) {
- ALOGE("drain -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "drain -- call failed: " << status << ".";
}
return status;
}
c2_status_t Codec2Client::Component::start() {
- Return<Status> transStatus = base()->start();
+ Return<Status> transStatus = mBase->start();
if (!transStatus.isOk()) {
- ALOGE("start -- transaction failed.");
+ LOG(ERROR) << "start -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
c2_status_t status =
static_cast<c2_status_t>(static_cast<Status>(transStatus));
if (status != C2_OK) {
- ALOGE("start -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "start -- call failed: " << status << ".";
}
return status;
}
c2_status_t Codec2Client::Component::stop() {
- Return<Status> transStatus = base()->stop();
+ Return<Status> transStatus = mBase->stop();
if (!transStatus.isOk()) {
- ALOGE("stop -- transaction failed.");
+ LOG(ERROR) << "stop -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
c2_status_t status =
static_cast<c2_status_t>(static_cast<Status>(transStatus));
if (status != C2_OK) {
- ALOGE("stop -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "stop -- call failed: " << status << ".";
}
mInputBuffersMutex.lock();
mInputBuffers.clear();
@@ -1098,16 +1168,15 @@
}
c2_status_t Codec2Client::Component::reset() {
- Return<Status> transStatus = base()->reset();
+ Return<Status> transStatus = mBase->reset();
if (!transStatus.isOk()) {
- ALOGE("reset -- transaction failed.");
+ LOG(ERROR) << "reset -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
c2_status_t status =
static_cast<c2_status_t>(static_cast<Status>(transStatus));
if (status != C2_OK) {
- ALOGE("reset -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "reset -- call failed: " << status << ".";
}
mInputBuffersMutex.lock();
mInputBuffers.clear();
@@ -1117,16 +1186,15 @@
}
c2_status_t Codec2Client::Component::release() {
- Return<Status> transStatus = base()->release();
+ Return<Status> transStatus = mBase->release();
if (!transStatus.isOk()) {
- ALOGE("release -- transaction failed.");
+ LOG(ERROR) << "release -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
c2_status_t status =
static_cast<c2_status_t>(static_cast<Status>(transStatus));
if (status != C2_OK) {
- ALOGE("release -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "release -- call failed: " << status << ".";
}
mInputBuffersMutex.lock();
mInputBuffers.clear();
@@ -1144,17 +1212,16 @@
igbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(surface);
}
- Return<Status> transStatus = base()->setOutputSurface(
+ Return<Status> transStatus = mBase->setOutputSurface(
static_cast<uint64_t>(blockPoolId), igbp);
if (!transStatus.isOk()) {
- ALOGE("setOutputSurface -- transaction failed.");
+ LOG(ERROR) << "setOutputSurface -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
c2_status_t status =
static_cast<c2_status_t>(static_cast<Status>(transStatus));
if (status != C2_OK) {
- ALOGE("setOutputSurface -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "setOutputSurface -- call failed: " << status << ".";
} else {
std::lock_guard<std::mutex> lock(mOutputBufferQueueMutex);
if (mOutputIgbp != surface) {
@@ -1162,7 +1229,8 @@
if (!surface) {
mOutputBqId = 0;
} else if (surface->getUniqueId(&mOutputBqId) != OK) {
- ALOGE("setOutputSurface -- cannot obtain bufferqueue id.");
+ LOG(ERROR) << "setOutputSurface -- "
+ "cannot obtain bufferqueue id.";
}
}
mOutputGeneration = generation;
@@ -1191,17 +1259,16 @@
outputGeneration,
&bqSlot);
if (status != OK) {
- ALOGW("queueToOutputSurface -- attaching failed.");
+ LOG(WARNING) << "queueToOutputSurface -- attaching failed.";
return INVALID_OPERATION;
}
status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
input, output);
if (status != OK) {
- ALOGE("queueToOutputSurface -- queueBuffer() failed "
- "on non-bufferqueue-based block. "
- "Error code = %d.",
- static_cast<int>(status));
+ LOG(ERROR) << "queueToOutputSurface -- queueBuffer() failed "
+ "on non-bufferqueue-based block. "
+ "Error = " << status << ".";
return status;
}
return OK;
@@ -1214,17 +1281,17 @@
mOutputBufferQueueMutex.unlock();
if (!outputIgbp) {
- ALOGV("queueToOutputSurface -- output surface is null.");
+ LOG(VERBOSE) << "queueToOutputSurface -- output surface is null.";
return NO_INIT;
}
if (bqId != outputBqId || generation != outputGeneration) {
if (!holdBufferQueueBlock(block, mOutputIgbp, mOutputBqId, mOutputGeneration)) {
- ALOGE("queueToOutputSurface -- migration fialed");
+ LOG(ERROR) << "queueToOutputSurface -- migration failed.";
return DEAD_OBJECT;
}
if (!getBufferQueueAssignment(block, &generation, &bqId, &bqSlot)) {
- ALOGE("queueToOutputSurface -- corrupted bq assignment");
+ LOG(ERROR) << "queueToOutputSurface -- corrupted bufferqueue assignment.";
return UNKNOWN_ERROR;
}
}
@@ -1232,49 +1299,77 @@
status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot),
input, output);
if (status != OK) {
- ALOGD("queueToOutputSurface -- queueBuffer() failed "
- "on bufferqueue-based block. "
- "Error code = %d.",
- static_cast<int>(status));
+ LOG(DEBUG) << "queueToOutputSurface -- queueBuffer() failed "
+ "on bufferqueue-based block. "
+ "Error = " << status << ".";
return status;
}
if (!yieldBufferQueueBlock(block)) {
- ALOGD("queueToOutputSurface -- cannot yield bufferqueue-based block "
- "to the bufferqueue.");
+ LOG(DEBUG) << "queueToOutputSurface -- cannot yield "
+ "bufferqueue-based block to the bufferqueue.";
return UNKNOWN_ERROR;
}
return OK;
}
-c2_status_t Codec2Client::Component::connectToOmxInputSurface(
- const sp<HGraphicBufferProducer>& producer,
- const sp<HGraphicBufferSource>& source) {
- Return<Status> transStatus = base()->connectToOmxInputSurface(
- producer, source);
+c2_status_t Codec2Client::Component::connectToInputSurface(
+ const std::shared_ptr<InputSurface>& inputSurface,
+ std::shared_ptr<InputSurfaceConnection>* connection) {
+ c2_status_t status;
+ Return<void> transStatus = mBase->connectToInputSurface(
+ inputSurface->mBase,
+ [&status, connection](
+ Status s, const sp<IInputSurfaceConnection>& c) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "connectToInputSurface -- call failed: "
+ << status << ".";
+ return;
+ }
+ *connection = std::make_shared<InputSurfaceConnection>(c);
+ });
if (!transStatus.isOk()) {
- ALOGE("connectToOmxInputSurface -- transaction failed.");
+ LOG(ERROR) << "connectToInputSurface -- transaction failed";
return C2_TRANSACTION_FAILED;
}
- c2_status_t status =
- static_cast<c2_status_t>(static_cast<Status>(transStatus));
- if (status != C2_OK) {
- ALOGE("connectToOmxInputSurface -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ return status;
+}
+
+c2_status_t Codec2Client::Component::connectToOmxInputSurface(
+ const sp<HGraphicBufferProducer>& producer,
+ const sp<HGraphicBufferSource>& source,
+ std::shared_ptr<InputSurfaceConnection>* connection) {
+ c2_status_t status;
+ Return<void> transStatus = mBase->connectToOmxInputSurface(
+ producer, source,
+ [&status, connection](
+ Status s, const sp<IInputSurfaceConnection>& c) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "connectToOmxInputSurface -- call failed: "
+ << status << ".";
+ return;
+ }
+ *connection = std::make_shared<InputSurfaceConnection>(c);
+ });
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "connectToOmxInputSurface -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
}
return status;
}
c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
- Return<Status> transStatus = base()->disconnectFromInputSurface();
+ Return<Status> transStatus = mBase->disconnectFromInputSurface();
if (!transStatus.isOk()) {
- ALOGE("disconnectToInputSurface -- transaction failed.");
+ LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
return C2_TRANSACTION_FAILED;
}
c2_status_t status =
static_cast<c2_status_t>(static_cast<Status>(transStatus));
if (status != C2_OK) {
- ALOGE("disconnectFromInputSurface -- call failed. "
- "Error code = %d", static_cast<int>(status));
+ LOG(DEBUG) << "disconnectFromInputSurface -- call failed: "
+ << status << ".";
}
return status;
}
@@ -1294,7 +1389,7 @@
if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
listener->onDeath(component);
} else {
- ALOGW("onDeath -- listener died.");
+ LOG(DEBUG) << "onDeath -- listener died.";
}
}
};
@@ -1304,93 +1399,68 @@
deathRecipient->component = component;
component->mDeathRecipient = deathRecipient;
- Return<bool> transResult = component->base()->linkToDeath(
+ Return<bool> transResult = component->mBase->linkToDeath(
component->mDeathRecipient, 0);
if (!transResult.isOk()) {
- ALOGE("setDeathListener -- failed transaction: linkToDeath.");
+ LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
return C2_TRANSACTION_FAILED;
}
if (!static_cast<bool>(transResult)) {
- ALOGE("setDeathListener -- linkToDeath call failed.");
+ LOG(DEBUG) << "setDeathListener -- linkToDeath() call failed.";
return C2_CORRUPTED;
}
return C2_OK;
}
// Codec2Client::InputSurface
-
-Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const {
- return static_cast<Base*>(mBase.get());
-}
-
-Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base) :
- mBase(base),
- mGraphicBufferProducer(new
+Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base)
+ : Configurable{
+ [base]() -> sp<IConfigurable> {
+ Return<sp<IConfigurable>> transResult =
+ base->getConfigurable();
+ return transResult.isOk() ?
+ static_cast<sp<IConfigurable>>(transResult) :
+ nullptr;
+ }()
+ },
+ mBase{base},
+ mGraphicBufferProducer{new
::android::hardware::graphics::bufferqueue::V1_0::utils::
- H2BGraphicBufferProducer(base)) {
+ H2BGraphicBufferProducer([base]() -> sp<HGraphicBufferProducer> {
+ Return<sp<HGraphicBufferProducer>> transResult =
+ base->getGraphicBufferProducer();
+ return transResult.isOk() ?
+ static_cast<sp<HGraphicBufferProducer>>(transResult) :
+ nullptr;
+ }())} {
}
-c2_status_t Codec2Client::InputSurface::connectToComponent(
- const std::shared_ptr<Codec2Client::Component>& component,
- std::shared_ptr<Connection>* connection) {
- c2_status_t status;
- Return<void> transStatus = base()->connectToComponent(
- component->base(),
- [&status, connection](
- Status s,
- const sp<IInputSurfaceConnection>& c) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- ALOGE("connectToComponent -- call failed. "
- "Error code = %d", static_cast<int>(status));
- return;
- }
- *connection = std::make_shared<Connection>(c);
- });
- if (!transStatus.isOk()) {
- ALOGE("connect -- transaction failed.");
- return C2_TRANSACTION_FAILED;
- }
- return status;
-}
-
-std::shared_ptr<Codec2Client::Configurable>
- Codec2Client::InputSurface::getConfigurable() const {
- Return<sp<IConfigurable>> transResult = base()->getConfigurable();
- if (!transResult.isOk()) {
- ALOGW("getConfigurable -- transaction failed.");
- return nullptr;
- }
- if (!static_cast<sp<IConfigurable>>(transResult)) {
- ALOGW("getConfigurable -- null pointer.");
- return nullptr;
- }
- return std::make_shared<Configurable>(transResult);
-}
-
-const sp<IGraphicBufferProducer>&
+sp<IGraphicBufferProducer>
Codec2Client::InputSurface::getGraphicBufferProducer() const {
return mGraphicBufferProducer;
}
-const sp<IInputSurface>& Codec2Client::InputSurface::getHalInterface() const {
+sp<IInputSurface> Codec2Client::InputSurface::getHalInterface() const {
return mBase;
}
// Codec2Client::InputSurfaceConnection
-
-Codec2Client::InputSurfaceConnection::Base*
- Codec2Client::InputSurfaceConnection::base() const {
- return static_cast<Base*>(mBase.get());
-}
-
Codec2Client::InputSurfaceConnection::InputSurfaceConnection(
- const sp<Codec2Client::InputSurfaceConnection::Base>& base) :
- mBase(base) {
+ const sp<IInputSurfaceConnection>& base)
+ : Configurable{
+ [base]() -> sp<IConfigurable> {
+ Return<sp<IConfigurable>> transResult =
+ base->getConfigurable();
+ return transResult.isOk() ?
+ static_cast<sp<IConfigurable>>(transResult) :
+ nullptr;
+ }()
+ },
+ mBase{base} {
}
c2_status_t Codec2Client::InputSurfaceConnection::disconnect() {
- Return<Status> transResult = base()->disconnect();
+ Return<Status> transResult = mBase->disconnect();
return static_cast<c2_status_t>(static_cast<Status>(transResult));
}
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index c48bf0c..f320ef3 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef CODEC2_HIDL_CLIENT_H_
-#define CODEC2_HIDL_CLIENT_H_
+#ifndef CODEC2_HIDL_CLIENT_H
+#define CODEC2_HIDL_CLIENT_H
#include <gui/IGraphicBufferProducer.h>
#include <codec2/hidl/1.0/types.h>
@@ -70,8 +70,8 @@
namespace c2 {
namespace V1_0 {
struct IConfigurable;
-struct IComponentInterface;
struct IComponent;
+struct IComponentInterface;
struct IComponentStore;
struct IInputSurface;
struct IInputSurfaceConnection;
@@ -146,10 +146,8 @@
Codec2ConfigurableClient(const sp<Base>& base);
protected:
- C2String mName;
sp<Base> mBase;
-
- Base* base() const;
+ C2String mName;
friend struct Codec2Client;
};
@@ -162,17 +160,17 @@
typedef Codec2ConfigurableClient Configurable;
- typedef Configurable Interface; // These two types may diverge in the future.
-
struct Component;
+ struct Interface;
+
struct InputSurface;
struct InputSurfaceConnection;
typedef Codec2Client Store;
- std::string getInstanceName() const { return mInstanceName; }
+ std::string getServiceName() const { return mServiceName; }
c2_status_t createComponent(
const C2String& name,
@@ -195,7 +193,7 @@
std::shared_ptr<C2ParamReflector> getParamReflector();
static std::shared_ptr<Codec2Client> CreateFromService(
- const char* instanceName,
+ const char* serviceName,
bool waitForService = true);
// Try to create a component with a given name from all known
@@ -218,10 +216,10 @@
static std::shared_ptr<InputSurface> CreateInputSurface();
// base cannot be null.
- Codec2Client(const sp<Base>& base, std::string instanceName);
+ Codec2Client(const sp<Base>& base, std::string serviceName);
protected:
- Base* base() const;
+ sp<Base> mBase;
// Finds the first store where the predicate returns OK, and returns the last
// predicate result. Uses key to remember the last store found, and if cached,
@@ -232,7 +230,7 @@
mutable std::mutex mMutex;
mutable bool mListed;
- std::string mInstanceName;
+ std::string mServiceName;
mutable std::vector<C2Component::Traits> mTraitsList;
mutable std::vector<std::unique_ptr<std::vector<std::string>>>
mAliasesBuffer;
@@ -241,6 +239,16 @@
mHostPoolManager;
};
+struct Codec2Client::Interface : public Codec2Client::Configurable {
+
+ typedef ::android::hardware::media::c2::V1_0::IComponentInterface Base;
+
+ Interface(const sp<Base>& base);
+
+protected:
+ sp<Base> mBase;
+};
+
struct Codec2Client::Listener {
// This is called when the component produces some output.
@@ -277,28 +285,12 @@
virtual void onInputBufferDone(
const std::shared_ptr<C2Buffer>& buffer) = 0;
- // This structure is used for transporting onFramesRendered() event to the
- // client in the case where the output buffers are obtained from a
- // bufferqueue.
- struct RenderedFrame {
- // The id of the bufferqueue.
- uint64_t bufferQueueId;
- // The slot of the buffer inside the bufferqueue.
- int32_t slotId;
- // The timestamp.
- int64_t timestampNs;
-
- RenderedFrame(uint64_t bufferQueueId, int32_t slotId,
- int64_t timestampNs)
- : bufferQueueId(bufferQueueId),
- slotId(slotId),
- timestampNs(timestampNs) {}
- RenderedFrame(const RenderedFrame&) = default;
- };
-
- // This is called when the component becomes aware of frames being rendered.
- virtual void onFramesRendered(
- const std::vector<RenderedFrame>& renderedFrames) = 0;
+ // This is called when the component becomes aware of a frame being
+ // rendered.
+ virtual void onFrameRendered(
+ uint64_t bufferQueueId,
+ int32_t slotId,
+ int64_t timestampNs) = 0;
virtual ~Listener();
@@ -373,9 +365,15 @@
const QueueBufferInput& input,
QueueBufferOutput* output);
+ // Connect to a given InputSurface.
+ c2_status_t connectToInputSurface(
+ const std::shared_ptr<InputSurface>& inputSurface,
+ std::shared_ptr<InputSurfaceConnection>* connection);
+
c2_status_t connectToOmxInputSurface(
const sp<HGraphicBufferProducer>& producer,
- const sp<HGraphicBufferSource>& source);
+ const sp<HGraphicBufferSource>& source,
+ std::shared_ptr<InputSurfaceConnection>* connection);
c2_status_t disconnectFromInputSurface();
@@ -385,7 +383,7 @@
~Component();
protected:
- Base* base() const;
+ sp<Base> mBase;
// Mutex for mInputBuffers and mInputBufferCount.
mutable std::mutex mInputBuffersMutex;
@@ -428,7 +426,7 @@
};
-struct Codec2Client::InputSurface {
+struct Codec2Client::InputSurface : public Codec2Client::Configurable {
public:
typedef ::android::hardware::media::c2::V1_0::IInputSurface Base;
@@ -439,22 +437,15 @@
typedef ::android::IGraphicBufferProducer IGraphicBufferProducer;
- c2_status_t connectToComponent(
- const std::shared_ptr<Component>& component,
- std::shared_ptr<Connection>* connection);
-
- std::shared_ptr<Configurable> getConfigurable() const;
-
- const sp<IGraphicBufferProducer>& getGraphicBufferProducer() const;
+ sp<IGraphicBufferProducer> getGraphicBufferProducer() const;
// Return the underlying IInputSurface.
- const sp<Base>& getHalInterface() const;
+ sp<Base> getHalInterface() const;
// base cannot be null.
InputSurface(const sp<Base>& base);
protected:
- Base* base() const;
sp<Base> mBase;
sp<IGraphicBufferProducer> mGraphicBufferProducer;
@@ -463,7 +454,7 @@
friend struct Component;
};
-struct Codec2Client::InputSurfaceConnection {
+struct Codec2Client::InputSurfaceConnection : public Codec2Client::Configurable {
typedef ::android::hardware::media::c2::V1_0::IInputSurfaceConnection Base;
@@ -473,7 +464,6 @@
InputSurfaceConnection(const sp<Base>& base);
protected:
- Base* base() const;
sp<Base> mBase;
friend struct Codec2Client::InputSurface;
@@ -481,5 +471,5 @@
} // namespace android
-#endif // CODEC2_HIDL_CLIENT_H_
+#endif // CODEC2_HIDL_CLIENT_H
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 852d6d6..10263de 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -143,8 +143,7 @@
if (mConnection != nullptr) {
return ALREADY_EXISTS;
}
- return toStatusT(mSurface->connectToComponent(comp, &mConnection),
- C2_OPERATION_InputSurface_connectToComponent);
+ return toStatusT(comp->connectToInputSurface(mSurface, &mConnection));
}
void disconnect() override {
@@ -162,7 +161,7 @@
status_t signalEndOfInputStream() override {
C2InputSurfaceEosTuning eos(true);
std::vector<std::unique_ptr<C2SettingResult>> failures;
- c2_status_t err = mSurface->getConfigurable()->config({&eos}, C2_MAY_BLOCK, &failures);
+ c2_status_t err = mSurface->config({&eos}, C2_MAY_BLOCK, &failures);
if (err != C2_OK) {
return UNKNOWN_ERROR;
}
@@ -495,10 +494,13 @@
codec->mCallback->onError(DEAD_OBJECT, ACTION_CODE_FATAL);
}
- virtual void onFramesRendered(
- const std::vector<RenderedFrame>& renderedFrames) override {
- // TODO
- (void)renderedFrames;
+ virtual void onFrameRendered(uint64_t bufferQueueId,
+ int32_t slotId,
+ int64_t timestampNs) override {
+ // TODO: implement
+ (void)bufferQueueId;
+ (void)slotId;
+ (void)timestampNs;
}
virtual void onInputBufferDone(
@@ -599,7 +601,7 @@
// set up preferred component store to access vendor store parameters
client = Codec2Client::CreateFromService("default", false);
if (client) {
- ALOGI("setting up '%s' as default (vendor) store", client->getInstanceName().c_str());
+ ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str());
SetPreferredCodec2ComponentStore(
std::make_shared<Codec2ClientInterfaceWrapper>(client));
}
@@ -956,16 +958,18 @@
std::shared_ptr<PersistentSurface> persistentSurface(CreateInputSurface());
if (persistentSurface->getHidlTarget()) {
- sp<IInputSurface> inputSurface = IInputSurface::castFrom(
+ sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(
persistentSurface->getHidlTarget());
- if (!inputSurface) {
+ if (!hidlInputSurface) {
ALOGE("Corrupted input surface");
mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
return;
}
+ std::shared_ptr<Codec2Client::InputSurface> inputSurface =
+ std::make_shared<Codec2Client::InputSurface>(hidlInputSurface);
err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
- std::make_shared<Codec2Client::InputSurface>(inputSurface)));
- bufferProducer = new H2BGraphicBufferProducer(inputSurface);
+ inputSurface));
+ bufferProducer = inputSurface->getGraphicBufferProducer();
} else {
int32_t width = 0;
(void)outputFormat->findInt32("width", &width);
@@ -1020,7 +1024,7 @@
ALOGD("ISConfig: no configuration");
}
- return surface->start();
+ return OK;
}
void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) {
@@ -1107,12 +1111,20 @@
}
sp<AMessage> inputFormat;
sp<AMessage> outputFormat;
+ status_t err2 = OK;
{
Mutexed<Config>::Locked config(mConfig);
inputFormat = config->mInputFormat;
outputFormat = config->mOutputFormat;
+ if (config->mInputSurface) {
+ err2 = config->mInputSurface->start();
+ }
}
- status_t err2 = mChannel->start(inputFormat, outputFormat);
+ if (err2 != OK) {
+ mCallback->onError(err2, ACTION_CODE_FATAL);
+ return;
+ }
+ err2 = mChannel->start(inputFormat, outputFormat);
if (err2 != OK) {
mCallback->onError(err2, ACTION_CODE_FATAL);
return;
@@ -1187,6 +1199,13 @@
}
{
+ Mutexed<Config>::Locked config(mConfig);
+ if (config->mInputSurface) {
+ config->mInputSurface->disconnect();
+ config->mInputSurface = nullptr;
+ }
+ }
+ {
Mutexed<State>::Locked state(mState);
if (state->get() == STOPPING) {
state->set(ALLOCATED);
@@ -1196,6 +1215,7 @@
}
void CCodec::initiateRelease(bool sendCallback /* = true */) {
+ bool clearInputSurfaceIfNeeded = false;
{
Mutexed<State>::Locked state(mState);
if (state->get() == RELEASED || state->get() == RELEASING) {
@@ -1217,9 +1237,23 @@
}
return;
}
+ if (state->get() == STARTING
+ || state->get() == RUNNING
+ || state->get() == STOPPING) {
+ // Input surface may have been started, so clean up is needed.
+ clearInputSurfaceIfNeeded = true;
+ }
state->set(RELEASING);
}
+ if (clearInputSurfaceIfNeeded) {
+ Mutexed<Config>::Locked config(mConfig);
+ if (config->mInputSurface) {
+ config->mInputSurface->disconnect();
+ config->mInputSurface = nullptr;
+ }
+ }
+
mChannel->stop();
// thiz holds strong ref to this while the thread is running.
sp<CCodec> thiz(this);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index b529cbc..9616e47 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -128,7 +128,9 @@
* and released successfully.
*/
virtual bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) = 0;
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) = 0;
/**
* Release the buffer that is no longer used by the codec process. Return
@@ -455,13 +457,18 @@
* \return true if the buffer is successfully released from a slot
* false otherwise
*/
- bool releaseSlot(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+ bool releaseSlot(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) {
sp<Codec2Buffer> clientBuffer;
size_t index = mBuffers.size();
for (size_t i = 0; i < mBuffers.size(); ++i) {
if (mBuffers[i].clientBuffer == buffer) {
clientBuffer = mBuffers[i].clientBuffer;
- mBuffers[i].clientBuffer.clear();
+ if (release) {
+ mBuffers[i].clientBuffer.clear();
+ }
index = i;
break;
}
@@ -470,8 +477,11 @@
ALOGV("[%s] %s: No matching buffer found", mName, __func__);
return false;
}
- std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
+ std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+ if (!result) {
+ result = clientBuffer->asC2Buffer();
+ mBuffers[index].compBuffer = result;
+ }
if (c2buffer) {
*c2buffer = result;
}
@@ -485,8 +495,8 @@
if (!compBuffer || compBuffer != c2buffer) {
continue;
}
- mBuffers[i].clientBuffer = nullptr;
mBuffers[i].compBuffer.reset();
+ ALOGV("[%s] codec released buffer #%zu", mName, i);
return true;
}
ALOGV("[%s] codec released an unknown buffer", mName);
@@ -597,7 +607,10 @@
* \return true if the buffer is successfully returned
* false otherwise
*/
- bool returnBuffer(const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
+ bool returnBuffer(
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) {
sp<Codec2Buffer> clientBuffer;
size_t index = mBuffers.size();
for (size_t i = 0; i < mBuffers.size(); ++i) {
@@ -606,7 +619,9 @@
ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu", mName, i);
}
clientBuffer = mBuffers[i].clientBuffer;
- mBuffers[i].ownedByClient = false;
+ if (release) {
+ mBuffers[i].ownedByClient = false;
+ }
index = i;
break;
}
@@ -616,8 +631,11 @@
return false;
}
ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
- std::shared_ptr<C2Buffer> result = clientBuffer->asC2Buffer();
- mBuffers[index].compBuffer = result;
+ std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
+ if (!result) {
+ result = clientBuffer->asC2Buffer();
+ mBuffers[index].compBuffer = result;
+ }
if (c2buffer) {
*c2buffer = result;
}
@@ -636,9 +654,9 @@
// This should not happen.
ALOGD("[%s] codec released a buffer owned by client "
"(index %zu)", mName, i);
- mBuffers[i].ownedByClient = false;
}
mBuffers[i].compBuffer.reset();
+ ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
return true;
}
}
@@ -723,8 +741,10 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.returnBuffer(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override {
+ return mImpl.returnBuffer(buffer, c2buffer, release);
}
bool expireComponentBuffer(
@@ -765,8 +785,10 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
}
bool expireComponentBuffer(
@@ -801,7 +823,7 @@
return std::move(array);
}
- virtual sp<Codec2Buffer> alloc(size_t size) const {
+ virtual sp<Codec2Buffer> alloc(size_t size) {
C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
std::shared_ptr<C2LinearBlock> block;
@@ -850,11 +872,12 @@
~EncryptedLinearInputBuffers() override {
}
- sp<Codec2Buffer> alloc(size_t size) const override {
+ sp<Codec2Buffer> alloc(size_t size) override {
sp<IMemory> memory;
- for (const Entry &entry : mMemoryVector) {
- if (entry.block.expired()) {
- memory = entry.memory;
+ size_t slot = 0;
+ for (; slot < mMemoryVector.size(); ++slot) {
+ if (mMemoryVector[slot].block.expired()) {
+ memory = mMemoryVector[slot].memory;
break;
}
}
@@ -864,10 +887,11 @@
std::shared_ptr<C2LinearBlock> block;
c2_status_t err = mPool->fetchLinearBlock(size, mUsage, &block);
- if (err != C2_OK) {
+ if (err != C2_OK || block == nullptr) {
return nullptr;
}
+ mMemoryVector[slot].block = block;
return new EncryptedLinearBlockBuffer(mFormat, block, memory, mHeapSeqNum);
}
@@ -907,8 +931,10 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
}
bool expireComponentBuffer(
@@ -971,14 +997,17 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer,
+ bool release) override {
+ return mImpl.releaseSlot(buffer, c2buffer, release);
}
bool expireComponentBuffer(
const std::shared_ptr<C2Buffer> &c2buffer) override {
return mImpl.expireComponentBuffer(c2buffer);
}
+
void flush() override {
// This is no-op by default unless we're in array mode where we need to keep
// track of the flushed work.
@@ -1016,7 +1045,7 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *) override {
+ const sp<MediaCodecBuffer> &, std::shared_ptr<C2Buffer> *, bool) override {
return false;
}
@@ -1111,7 +1140,7 @@
bool releaseBuffer(
const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.returnBuffer(buffer, c2buffer);
+ return mImpl.returnBuffer(buffer, c2buffer, true);
}
void flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) override {
@@ -1171,6 +1200,9 @@
size_t *index,
sp<MediaCodecBuffer> *clientBuffer) override {
sp<Codec2Buffer> newBuffer = wrap(buffer);
+ if (newBuffer == nullptr) {
+ return NO_MEMORY;
+ }
newBuffer->setFormat(mFormat);
*index = mImpl.assignSlot(newBuffer);
*clientBuffer = newBuffer;
@@ -1190,8 +1222,9 @@
}
bool releaseBuffer(
- const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) override {
- return mImpl.releaseSlot(buffer, c2buffer);
+ const sp<MediaCodecBuffer> &buffer,
+ std::shared_ptr<C2Buffer> *c2buffer) override {
+ return mImpl.releaseSlot(buffer, c2buffer, true);
}
void flush(
@@ -1263,6 +1296,10 @@
return nullptr;
}
sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
+ if (clientBuffer == nullptr) {
+ ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
+ return nullptr;
+ }
submit(clientBuffer);
return clientBuffer;
}
@@ -1303,6 +1340,10 @@
[lbp = mLocalBufferPool](size_t capacity) {
return lbp->newBuffer(capacity);
});
+ if (c2buffer == nullptr) {
+ ALOGD("[%s] ConstGraphicBlockBuffer::AllocateEmpty failed", mName);
+ return nullptr;
+ }
c2buffer->setRange(0, 0);
return c2buffer;
} else {
@@ -1478,6 +1519,11 @@
mKey = C2Config::ORDINAL;
}
+void CCodecBufferChannel::ReorderStash::flush() {
+ mPending.clear();
+ mStash.clear();
+}
+
void CCodecBufferChannel::ReorderStash::setDepth(uint32_t depth) {
mPending.splice(mPending.end(), mStash);
mDepth = depth;
@@ -1615,7 +1661,7 @@
if (buffer->size() > 0u) {
Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
std::shared_ptr<C2Buffer> c2buffer;
- if (!(*buffers)->releaseBuffer(buffer, &c2buffer)) {
+ if (!(*buffers)->releaseBuffer(buffer, &c2buffer, false)) {
return -ENOENT;
}
work->input.buffers.push_back(c2buffer);
@@ -1645,6 +1691,7 @@
work->input.ordinal.customOrdinal = timeUs;
work->input.buffers.clear();
work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
+ work->worklets.emplace_back(new C2Worklet);
items.clear();
items.push_back(std::move(work));
@@ -1652,6 +1699,10 @@
}
if (err == C2_OK) {
mCCodecCallback->onWorkQueued(eos);
+
+ Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
+ bool released = (*buffers)->releaseBuffer(buffer, nullptr, true);
+ ALOGV("[%s] queueInputBuffer: buffer %sreleased", mName, released ? "" : "not ");
}
feedInputBufferIfAvailableInternal();
@@ -1980,7 +2031,7 @@
bool released = false;
{
Mutexed<std::unique_ptr<InputBuffers>>::Locked buffers(mInputBuffers);
- if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr)) {
+ if (*buffers && (*buffers)->releaseBuffer(buffer, nullptr, true)) {
buffers.unlock();
released = true;
mAvailablePipelineCapacity.freeInputSlots(1, "discardBuffer");
@@ -2445,7 +2496,6 @@
mSync.stop();
mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
if (mInputSurface != nullptr) {
- mInputSurface->disconnect();
mInputSurface.reset();
}
}
@@ -2481,6 +2531,7 @@
Mutexed<std::unique_ptr<OutputBuffers>>::Locked buffers(mOutputBuffers);
(*buffers)->flush(flushedWork);
}
+ mReorderStash.lock()->flush();
}
void CCodecBufferChannel::onWorkDone(
@@ -2708,6 +2759,9 @@
status_t err = (*buffers)->registerBuffer(entry.buffer, &index, &outBuffer);
if (err != OK) {
if (err != WOULD_BLOCK) {
+ if (!(*buffers)->isArrayMode()) {
+ *buffers = (*buffers)->toArrayMode(mNumOutputSlots);
+ }
OutputBuffersArray *array = (OutputBuffersArray *)buffers->get();
array->realloc(entry.buffer);
mCCodecCallback->onOutputBuffersChanged();
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index fd806b7..ebc1491 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -359,6 +359,7 @@
ReorderStash();
void clear();
+ void flush();
void setDepth(uint32_t depth);
void setKey(C2Config::ordinal_key_t key);
bool pop(Entry *entry);
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 597e8f3..2dec42e 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -451,6 +451,9 @@
}
bool setBackBuffer(const sp<ABuffer> &backBuffer) {
+ if (backBuffer == nullptr) {
+ return false;
+ }
if (backBuffer->capacity() < mBackBufferSize) {
return false;
}
diff --git a/media/codec2/sfplugin/Codec2InfoBuilder.cpp b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
index a8cc62d..5f0dd0b 100644
--- a/media/codec2/sfplugin/Codec2InfoBuilder.cpp
+++ b/media/codec2/sfplugin/Codec2InfoBuilder.cpp
@@ -44,6 +44,7 @@
#include <cutils/native_handle.h>
#include <media/omx/1.0/WOmxNode.h>
#include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/foundation/ALookup.h>
#include <media/stagefright/foundation/MediaDefs.h>
#include <media/stagefright/omx/OMXUtils.h>
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
@@ -299,7 +300,6 @@
// OMX components don't have aliases
for (const MediaCodecsXmlParser::Type &type : properties.typeMap) {
const std::string &mediaType = type.first;
-
std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
info->addMediaType(mediaType.c_str());
const MediaCodecsXmlParser::AttributeMap &attrMap = type.second;
@@ -376,7 +376,7 @@
}
bool surfaceTest(Codec2Client::CreateInputSurface());
- if (option == 0 || !surfaceTest) {
+ if (option == 0 || (option != 4 && !surfaceTest)) {
buildOmxInfo(parser, writer);
}
diff --git a/media/codec2/sfplugin/utils/Android.bp b/media/codec2/sfplugin/utils/Android.bp
index eb6c3e9..8c8f025 100644
--- a/media/codec2/sfplugin/utils/Android.bp
+++ b/media/codec2/sfplugin/utils/Android.bp
@@ -26,6 +26,10 @@
"libutils",
],
+ static_libs: [
+ "libyuv_static",
+ ],
+
sanitize: {
cfi: true,
misc_undefined: [
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
index 84d22a3..6b8663f 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "Codec2BufferUtils"
#include <utils/Log.h>
+#include <libyuv.h>
+
#include <list>
#include <mutex>
@@ -62,14 +64,10 @@
*/
template<bool ToMediaImage, typename View, typename ImagePixel>
static status_t _ImageCopy(View &view, const MediaImage2 *img, ImagePixel *imgBase) {
- // TODO: more efficient copying --- e.g. one row at a time, copying
- // interleaved planes together, etc.
+ // TODO: more efficient copying --- e.g. copy interleaved planes together, etc.
const C2PlanarLayout &layout = view.layout();
const size_t bpp = divUp(img->mBitDepthAllocated, 8u);
- if (view.width() != img->mWidth
- || view.height() != img->mHeight) {
- return BAD_VALUE;
- }
+
for (uint32_t i = 0; i < layout.numPlanes; ++i) {
typename std::conditional<ToMediaImage, uint8_t, const uint8_t>::type *imgRow =
imgBase + img->mPlane[i].mOffset;
@@ -120,10 +118,72 @@
} // namespace
status_t ImageCopy(uint8_t *imgBase, const MediaImage2 *img, const C2GraphicView &view) {
+ if (view.width() != img->mWidth || view.height() != img->mHeight) {
+ return BAD_VALUE;
+ }
+ if ((IsNV12(view) && IsI420(img)) || (IsI420(view) && IsNV12(img))) {
+ // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+ const uint8_t* src_y = view.data()[0];
+ const uint8_t* src_u = view.data()[1];
+ const uint8_t* src_v = view.data()[2];
+ int32_t src_stride_y = view.layout().planes[0].rowInc;
+ int32_t src_stride_u = view.layout().planes[1].rowInc;
+ int32_t src_stride_v = view.layout().planes[2].rowInc;
+ uint8_t* dst_y = imgBase + img->mPlane[0].mOffset;
+ uint8_t* dst_u = imgBase + img->mPlane[1].mOffset;
+ uint8_t* dst_v = imgBase + img->mPlane[2].mOffset;
+ int32_t dst_stride_y = img->mPlane[0].mRowInc;
+ int32_t dst_stride_u = img->mPlane[1].mRowInc;
+ int32_t dst_stride_v = img->mPlane[2].mRowInc;
+ if (IsNV12(view) && IsI420(img)) {
+ if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+ dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+ view.height())) {
+ return OK;
+ }
+ } else {
+ if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+ dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+ view.height())) {
+ return OK;
+ }
+ }
+ }
return _ImageCopy<true>(view, img, imgBase);
}
status_t ImageCopy(C2GraphicView &view, const uint8_t *imgBase, const MediaImage2 *img) {
+ if (view.width() != img->mWidth || view.height() != img->mHeight) {
+ return BAD_VALUE;
+ }
+ if ((IsNV12(img) && IsI420(view)) || (IsI420(img) && IsNV12(view))) {
+ // Take shortcuts to use libyuv functions between NV12 and I420 conversion.
+ const uint8_t* src_y = imgBase + img->mPlane[0].mOffset;
+ const uint8_t* src_u = imgBase + img->mPlane[1].mOffset;
+ const uint8_t* src_v = imgBase + img->mPlane[2].mOffset;
+ int32_t src_stride_y = img->mPlane[0].mRowInc;
+ int32_t src_stride_u = img->mPlane[1].mRowInc;
+ int32_t src_stride_v = img->mPlane[2].mRowInc;
+ uint8_t* dst_y = view.data()[0];
+ uint8_t* dst_u = view.data()[1];
+ uint8_t* dst_v = view.data()[2];
+ int32_t dst_stride_y = view.layout().planes[0].rowInc;
+ int32_t dst_stride_u = view.layout().planes[1].rowInc;
+ int32_t dst_stride_v = view.layout().planes[2].rowInc;
+ if (IsNV12(img) && IsI420(view)) {
+ if (!libyuv::NV12ToI420(src_y, src_stride_y, src_u, src_stride_u, dst_y, dst_stride_y,
+ dst_u, dst_stride_u, dst_v, dst_stride_v, view.width(),
+ view.height())) {
+ return OK;
+ }
+ } else {
+ if (!libyuv::I420ToNV12(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
+ dst_y, dst_stride_y, dst_u, dst_stride_u, view.width(),
+ view.height())) {
+ return OK;
+ }
+ }
+ }
return _ImageCopy<false>(view, img, imgBase);
}
@@ -151,6 +211,65 @@
&& layout.planes[layout.PLANE_V].rowSampling == 2);
}
+bool IsNV12(const C2GraphicView &view) {
+ if (!IsYUV420(view)) {
+ return false;
+ }
+ const C2PlanarLayout &layout = view.layout();
+ return (layout.rootPlanes == 2
+ && layout.planes[layout.PLANE_U].colInc == 2
+ && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+ && layout.planes[layout.PLANE_U].offset == 0
+ && layout.planes[layout.PLANE_V].colInc == 2
+ && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_U
+ && layout.planes[layout.PLANE_V].offset == 1);
+}
+
+bool IsI420(const C2GraphicView &view) {
+ if (!IsYUV420(view)) {
+ return false;
+ }
+ const C2PlanarLayout &layout = view.layout();
+ return (layout.rootPlanes == 3
+ && layout.planes[layout.PLANE_U].colInc == 1
+ && layout.planes[layout.PLANE_U].rootIx == layout.PLANE_U
+ && layout.planes[layout.PLANE_U].offset == 0
+ && layout.planes[layout.PLANE_V].colInc == 1
+ && layout.planes[layout.PLANE_V].rootIx == layout.PLANE_V
+ && layout.planes[layout.PLANE_V].offset == 0);
+}
+
+bool IsYUV420(const MediaImage2 *img) {
+ return (img->mType == MediaImage2::MEDIA_IMAGE_TYPE_YUV
+ && img->mNumPlanes == 3
+ && img->mBitDepth == 8
+ && img->mBitDepthAllocated == 8
+ && img->mPlane[0].mHorizSubsampling == 1
+ && img->mPlane[0].mVertSubsampling == 1
+ && img->mPlane[1].mHorizSubsampling == 2
+ && img->mPlane[1].mVertSubsampling == 2
+ && img->mPlane[2].mHorizSubsampling == 2
+ && img->mPlane[2].mVertSubsampling == 2);
+}
+
+bool IsNV12(const MediaImage2 *img) {
+ if (!IsYUV420(img)) {
+ return false;
+ }
+ return (img->mPlane[1].mColInc == 2
+ && img->mPlane[2].mColInc == 2
+ && (img->mPlane[2].mOffset - img->mPlane[1].mOffset == 1));
+}
+
+bool IsI420(const MediaImage2 *img) {
+ if (!IsYUV420(img)) {
+ return false;
+ }
+ return (img->mPlane[1].mColInc == 1
+ && img->mPlane[2].mColInc == 1
+ && img->mPlane[2].mOffset > img->mPlane[1].mOffset);
+}
+
MediaImage2 CreateYUV420PlanarMediaImage2(
uint32_t width, uint32_t height, uint32_t stride, uint32_t vstride) {
return MediaImage2 {
diff --git a/media/codec2/sfplugin/utils/Codec2BufferUtils.h b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
index eaf6776..afadf00 100644
--- a/media/codec2/sfplugin/utils/Codec2BufferUtils.h
+++ b/media/codec2/sfplugin/utils/Codec2BufferUtils.h
@@ -91,6 +91,31 @@
bool IsYUV420(const C2GraphicView &view);
/**
+ * Returns true iff a view has a NV12 layout.
+ */
+bool IsNV12(const C2GraphicView &view);
+
+/**
+ * Returns true iff a view has a I420 layout.
+ */
+bool IsI420(const C2GraphicView &view);
+
+/**
+ * Returns true iff a MediaImage2 has a YUV 420 888 layout.
+ */
+bool IsYUV420(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a NV12 layout.
+ */
+bool IsNV12(const MediaImage2 *img);
+
+/**
+ * Returns true iff a MediaImage2 has a I420 layout.
+ */
+bool IsI420(const MediaImage2 *img);
+
+/**
* A raw memory block to use for internal buffers.
*
* TODO: replace this with C2LinearBlocks from a private C2BlockPool
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 6e71b98..7bf3d64 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -192,7 +192,7 @@
int slot;
ALOGV("tries to dequeue buffer");
Return<void> transStatus = mProducer->dequeueBuffer(
- width, height, pixelFormat, androidUsage.asGrallocUsage(), true,
+ width, height, pixelFormat, androidUsage.asGrallocUsage(), false,
[&status, &slot, &fence](
int32_t tStatus, int32_t tSlot, hidl_handle const& tFence,
HGraphicBufferProducer::FrameEventHistoryDelta const& tTs) {
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 84fbcee..8854631 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -581,6 +581,7 @@
CHECK(mGroup == NULL);
mGroup = group;
mMaxBufferSize = getMaxBlockSize() * getChannels() * getOutputSampleSize();
+ AMediaFormat_setInt32(mTrackMetadata, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, mMaxBufferSize);
mGroup->add_buffer(mMaxBufferSize);
}
@@ -667,7 +668,7 @@
: mDataSource(dataSource),
mTrackMetadata(trackMetadata),
mOutputFloat(outputFloat),
- mParser(new FLACParser(mDataSource, outputFloat)),
+ mParser(new FLACParser(mDataSource, outputFloat, 0, mTrackMetadata)),
mInitCheck(mParser->initCheck()),
mStarted(false)
{
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 237f9c8..ac54116 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1635,9 +1635,8 @@
case FOURCC(".mp3"):
case 0x6D730055: // "ms U" mp3 audio
{
- if (mIsQT && chunk_type == FOURCC("mp4a")
- && depth >= 1 && mPath[depth - 1] == FOURCC("wave")) {
- // Ignore mp4a embedded in QT wave atom
+ if (mIsQT && depth >= 1 && mPath[depth - 1] == FOURCC("wave")) {
+ // Ignore all atoms embedded in QT wave atom
*offset += chunk_size;
break;
}
@@ -1666,7 +1665,7 @@
off64_t stop_offset = *offset + chunk_size;
*offset = data_offset + sizeof(buffer);
- if (mIsQT && chunk_type == FOURCC("mp4a")) {
+ if (mIsQT) {
if (version == 1) {
if (mDataSource->readAt(*offset, buffer, 16) < 16) {
return ERROR_IO;
@@ -1995,6 +1994,13 @@
*offset += chunk_size;
+ if (depth >= 1 && mPath[depth - 1] != FOURCC("stbl")) {
+ char chunk[5];
+ MakeFourCCString(mPath[depth - 1], chunk);
+ ALOGW("stts's parent box (%s) is not stbl, skip it.", chunk);
+ break;
+ }
+
status_t err =
mLastTrack->sampleTable->setTimeToSampleParams(
data_offset, chunk_data_size);
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 2a94671..0f0c72c 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -24,6 +24,8 @@
header_libs: [
"libbase_headers",
+ "libstagefright_headers",
+ "libmedia_headers",
],
static_libs: [
@@ -31,7 +33,7 @@
"libstagefright_foundation_without_imemory",
"libstagefright_mpeg2support",
"libutils",
- "libstagefright",
+ "libstagefright_mpeg2extractor",
"libstagefright_esds",
],
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 596c1c8..ba40690 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -983,7 +983,7 @@
size_t denom = numerator - kMaxNumTOCEntries;
size_t accum = 0;
- for (ssize_t i = mTableOfContents.size() - 1; i >= 0; --i) {
+ for (ssize_t i = mTableOfContents.size(); i > 0; --i) {
accum += denom;
if (accum >= numerator) {
mTableOfContents.removeAt(i);
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 3b03601..ec270f3 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -713,3 +713,7 @@
aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
}
+
+bool AudioStreamInternal::isClockModelInControl() const {
+ return isActive() && mAudioEndpoint.isFreeRunning() && mClockModel.isRunning();
+}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 1c88f52..86c4698 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -144,6 +144,14 @@
*/
bool isInService() const { return mInService; }
+ /**
+ * Is the service FIFO position currently controlled by the AAudio service or HAL,
+ * or set based on the Clock Model.
+ *
+ * @return true if the ClockModel is currently determining the FIFO position
+ */
+ bool isClockModelInControl() const;
+
IsochronousClockModel mClockModel; // timing model for chasing the HAL
AudioEndpoint mAudioEndpoint; // source for reads or sink for writes
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index 7dcb620..a6cc45b 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -210,17 +210,12 @@
}
int64_t AudioStreamInternalCapture::getFramesWritten() {
- int64_t framesWrittenHardware;
- if (isActive()) {
- framesWrittenHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
- } else {
- framesWrittenHardware = mAudioEndpoint.getDataWriteCounter();
- }
- // Prevent retrograde motion.
+ const int64_t framesWrittenHardware = isClockModelInControl()
+ ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
+ : mAudioEndpoint.getDataWriteCounter();
+ // Add service offset and prevent retrograde motion.
mLastFramesWritten = std::max(mLastFramesWritten,
framesWrittenHardware + mFramesOffsetFromService);
- //ALOGD("getFramesWritten() returns %lld",
- // (long long)mLastFramesWritten);
return mLastFramesWritten;
}
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 6af8e7d..e1443d9 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -242,27 +242,17 @@
return framesWritten;
}
-int64_t AudioStreamInternalPlay::getFramesRead()
-{
- int64_t framesReadHardware;
- if (isActive()) {
- framesReadHardware = mClockModel.convertTimeToPosition(AudioClock::getNanoseconds());
- } else {
- framesReadHardware = mAudioEndpoint.getDataReadCounter();
- }
- int64_t framesRead = framesReadHardware + mFramesOffsetFromService;
- // Prevent retrograde motion.
- if (framesRead < mLastFramesRead) {
- framesRead = mLastFramesRead;
- } else {
- mLastFramesRead = framesRead;
- }
- return framesRead;
+int64_t AudioStreamInternalPlay::getFramesRead() {
+ const int64_t framesReadHardware = isClockModelInControl()
+ ? mClockModel.convertTimeToPosition(AudioClock::getNanoseconds())
+ : mAudioEndpoint.getDataReadCounter();
+ // Add service offset and prevent retrograde motion.
+ mLastFramesRead = std::max(mLastFramesRead, framesReadHardware + mFramesOffsetFromService);
+ return mLastFramesRead;
}
-int64_t AudioStreamInternalPlay::getFramesWritten()
-{
- int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
+int64_t AudioStreamInternalPlay::getFramesWritten() {
+ const int64_t framesWritten = mAudioEndpoint.getDataWriteCounter()
+ mFramesOffsetFromService;
return framesWritten;
}
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 95b52be..747d0e1 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -60,10 +60,14 @@
mState = STATE_STOPPED;
}
-bool IsochronousClockModel::isStarting() {
+bool IsochronousClockModel::isStarting() const {
return mState == STATE_STARTING;
}
+bool IsochronousClockModel::isRunning() const {
+ return mState == STATE_RUNNING;
+}
+
void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) {
// ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
// (long long)framePosition,
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 7182376..46ca48e 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -36,7 +36,15 @@
void start(int64_t nanoTime);
void stop(int64_t nanoTime);
- bool isStarting();
+ /**
+ * @return true if the model is starting up
+ */
+ bool isStarting() const;
+
+ /**
+ * @return true if the model is running and producing valid results
+ */
+ bool isRunning() const;
void processTimestamp(int64_t framePosition, int64_t nanoTime);
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index f550089..4a65fc9 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -326,16 +326,13 @@
if (mAudioRecord.get() == nullptr) {
return AAUDIO_ERROR_INVALID_STATE;
}
- // Get current position so we can detect when the track is recording.
- status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
- if (err != OK) {
- return AAudioConvert_androidToAAudioResult(err);
- }
- // Enable callback before starting AudioTrack to avoid shutting
+ // Enable callback before starting AudioRecord to avoid shutting
// down because of a race condition.
mCallbackEnabled.store(true);
- err = mAudioRecord->start();
+ mFramesWritten.reset32(); // service writes frames
+ mTimestampPosition.reset32();
+ status_t err = mAudioRecord->start(); // resets position to zero
if (err != OK) {
return AAudioConvert_androidToAAudioResult(err);
} else {
@@ -349,12 +346,10 @@
return AAUDIO_ERROR_INVALID_STATE;
}
setState(AAUDIO_STREAM_STATE_STOPPING);
- incrementFramesWritten(getFramesRead() - getFramesWritten()); // TODO review
- mTimestampPosition.set(getFramesRead());
+ mFramesWritten.catchUpTo(getFramesRead());
+ mTimestampPosition.catchUpTo(getFramesRead());
mAudioRecord->stop();
mCallbackEnabled.store(false);
- mFramesWritten.reset32(); // service writes frames, service position reset on flush
- mTimestampPosition.reset32();
// Pass false to prevent errorCallback from being called after disconnect
// when app has already requested a stop().
return checkForDisconnectRequest(false);
@@ -368,10 +363,12 @@
switch (getState()) {
// TODO add better state visibility to AudioRecord
case AAUDIO_STREAM_STATE_STARTING:
+ // When starting, the position will begin at zero and then go positive.
+ // The position can wrap but by that time the state will not be STARTING.
err = mAudioRecord->getPosition(&position);
if (err != OK) {
result = AAudioConvert_androidToAAudioResult(err);
- } else if (position != mPositionWhenStarting) {
+ } else if (position > 0) {
setState(AAUDIO_STREAM_STATE_STARTED);
}
break;
@@ -504,12 +501,12 @@
switch (getState()) {
case AAUDIO_STREAM_STATE_STARTING:
case AAUDIO_STREAM_STATE_STARTED:
- case AAUDIO_STREAM_STATE_STOPPING:
result = mAudioRecord->getPosition(&position);
if (result == OK) {
mFramesWritten.update32(position);
}
break;
+ case AAUDIO_STREAM_STATE_STOPPING:
default:
break;
}
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index c995e99..ff95aed 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -323,8 +323,8 @@
}
setState(AAUDIO_STREAM_STATE_STOPPING);
- incrementFramesRead(getFramesWritten() - getFramesRead()); // TODO review
- mTimestampPosition.set(getFramesWritten());
+ mFramesRead.catchUpTo(getFramesWritten());
+ mTimestampPosition.catchUpTo(getFramesWritten());
mFramesRead.reset32(); // service reads frames, service position reset on stop
mTimestampPosition.reset32();
mAudioTrack->stop();
diff --git a/media/libaaudio/src/utility/MonotonicCounter.h b/media/libaaudio/src/utility/MonotonicCounter.h
index 5833eab..63add4e 100644
--- a/media/libaaudio/src/utility/MonotonicCounter.h
+++ b/media/libaaudio/src/utility/MonotonicCounter.h
@@ -41,10 +41,12 @@
}
/**
- * set the current value of the counter
+ * advance the current value to match the counter
*/
- void set(int64_t counter) {
- mCounter64 = counter;
+ void catchUpTo(int64_t counter) {
+ if ((counter - mCounter64) > 0) {
+ mCounter64 = counter;
+ }
}
/**
diff --git a/media/libaaudio/tests/test_clock_model.cpp b/media/libaaudio/tests/test_clock_model.cpp
index 3c09025..7f7abbd 100644
--- a/media/libaaudio/tests/test_clock_model.cpp
+++ b/media/libaaudio/tests/test_clock_model.cpp
@@ -43,13 +43,47 @@
}
void TearDown() {
-
}
~ClockModelTestFixture() {
// cleanup any pending stuff, but no exceptions allowed
}
+ // Test processing of timestamps when the hardware may be slightly off from
+ // the expected sample rate.
+ void checkDriftingClock(double hardwareFramesPerSecond, int numLoops) {
+ const int64_t startTimeNanos = 500000000; // arbitrary
+ model.start(startTimeNanos);
+
+ const int64_t startPositionFrames = HW_FRAMES_PER_BURST; // hardware
+ // arbitrary time for first burst
+ const int64_t markerTime = startTimeNanos + NANOS_PER_MILLISECOND
+ + (200 * NANOS_PER_MICROSECOND);
+
+ // Should set initial marker.
+ model.processTimestamp(startPositionFrames, markerTime);
+ ASSERT_EQ(startPositionFrames, model.convertTimeToPosition(markerTime));
+
+ double elapsedTimeSeconds = startTimeNanos / (double) NANOS_PER_SECOND;
+ for (int i = 0; i < numLoops; i++) {
+ // Calculate random delay over several bursts.
+ const double timeDelaySeconds = 10.0 * drand48() * NANOS_PER_BURST / NANOS_PER_SECOND;
+ elapsedTimeSeconds += timeDelaySeconds;
+ const int64_t elapsedTimeNanos = (int64_t)(elapsedTimeSeconds * NANOS_PER_SECOND);
+ const int64_t currentTimeNanos = startTimeNanos + elapsedTimeNanos;
+ // Simulate DSP running at the specified rate.
+ const int64_t currentTimeFrames = startPositionFrames +
+ (int64_t)(hardwareFramesPerSecond * elapsedTimeSeconds);
+ const int64_t numBursts = currentTimeFrames / HW_FRAMES_PER_BURST;
+ const int64_t alignedPosition = startPositionFrames + (numBursts * HW_FRAMES_PER_BURST);
+
+ // Apply drifting timestamp.
+ model.processTimestamp(alignedPosition, currentTimeNanos);
+
+ ASSERT_EQ(alignedPosition, model.convertTimeToPosition(currentTimeNanos));
+ }
+ }
+
IsochronousClockModel model;
};
@@ -95,7 +129,6 @@
}
// timestamps moves the window if outside the bounds
-// TODO test nudging the window
TEST_F(ClockModelTestFixture, clock_timestamp) {
const int64_t startTime = 100000000;
model.start(startTime);
@@ -113,3 +146,21 @@
// convertPositionToTime rounds up
EXPECT_EQ(markerTime + NANOS_PER_BURST, model.convertPositionToTime(position + 17));
}
+
+#define NUM_LOOPS_DRIFT 10000
+
+// test nudging the window by using a drifting HW clock
+TEST_F(ClockModelTestFixture, clock_no_drift) {
+ checkDriftingClock(SAMPLE_RATE, NUM_LOOPS_DRIFT);
+}
+
+// These slow drift rates caused errors when I disabled the code that handles
+// drifting in the clock model. So I think the test is valid.
+// It is unlikely that real hardware would be off by more than this amount.
+TEST_F(ClockModelTestFixture, clock_slow_drift) {
+ checkDriftingClock(0.998 * SAMPLE_RATE, NUM_LOOPS_DRIFT);
+}
+
+TEST_F(ClockModelTestFixture, clock_fast_drift) {
+ checkDriftingClock(1.002 * SAMPLE_RATE, NUM_LOOPS_DRIFT);
+}
\ No newline at end of file
diff --git a/media/libaaudio/tests/test_return_stop.cpp b/media/libaaudio/tests/test_return_stop.cpp
index 9a9e00c..1252dd3 100644
--- a/media/libaaudio/tests/test_return_stop.cpp
+++ b/media/libaaudio/tests/test_return_stop.cpp
@@ -140,7 +140,7 @@
printf("%s() - error = %d\n", __func__, error);
}
-void usage() {
+static void s_usage() {
printf("test_return_stop [-i] [-x] [-n] [-c]\n");
printf(" -i direction INPUT, otherwise OUTPUT\n");
printf(" -x sharing mode EXCLUSIVE, otherwise SHARED\n");
@@ -148,6 +148,28 @@
printf(" -c always return CONTINUE from callback, not STOP\n");
}
+/**
+ * @return 0 is OK, -1 for error
+ */
+static int s_checkEnginePositions(AudioEngine *engine) {
+ const int64_t framesRead = AAudioStream_getFramesRead(engine->stream);
+ const int64_t framesWritten = AAudioStream_getFramesWritten(engine->stream);
+ const int32_t delta = (int32_t)(framesWritten - framesRead);
+ printf("playing framesRead = %7d, framesWritten = %7d"
+ ", delta = %4d, framesCalled = %6d, callbackCount = %4d\n",
+ (int32_t) framesRead,
+ (int32_t) framesWritten,
+ delta,
+ engine->framesCalled.load(),
+ engine->callbackCount.load()
+ );
+ if (delta > AAudioStream_getBufferCapacityInFrames(engine->stream)) {
+ printf("ERROR - delta > capacity\n");
+ return -1;
+ }
+ return 0;
+}
+
int main(int argc, char **argv) {
(void) argc;
(void) argv;
@@ -188,12 +210,12 @@
sharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
break;
default:
- usage();
+ s_usage();
exit(EXIT_FAILURE);
break;
}
} else {
- usage();
+ s_usage();
exit(EXIT_FAILURE);
break;
}
@@ -201,12 +223,20 @@
result = s_OpenAudioStream(&engine, direction, sharingMode, perfMode);
if (result != AAUDIO_OK) {
- printf("s_OpenAudioStream returned %s",
+ printf("s_OpenAudioStream returned %s\n",
AAudio_convertResultToText(result));
errorCount++;
}
int32_t framesPerBurst = AAudioStream_getFramesPerBurst(engine.stream);
+ // Use double buffered stream.
+ const int32_t bufferSize = AAudioStream_setBufferSizeInFrames(engine.stream, 2 * framesPerBurst);
+ if (bufferSize < 0) {
+ printf("AAudioStream_setBufferSizeInFrames returned %s\n",
+ AAudio_convertResultToText(bufferSize));
+ errorCount++;
+ }
+
// Check to see what kind of stream we actually got.
int32_t deviceId = AAudioStream_getDeviceId(engine.stream);
aaudio_performance_mode_t actualPerfMode = AAudioStream_getPerformanceMode(engine.stream);
@@ -235,21 +265,14 @@
if (result == AAUDIO_OK) {
const int watchLoops = LOOP_DURATION_MSEC / SLEEP_DURATION_MSEC;
for (int i = watchLoops; i > 0; i--) {
- printf("playing silence #%02d, framesRead = %7d, framesWritten = %7d,"
- " framesCalled = %6d, callbackCount = %4d\n",
- i,
- (int32_t) AAudioStream_getFramesRead(engine.stream),
- (int32_t) AAudioStream_getFramesWritten(engine.stream),
- engine.framesCalled.load(),
- engine.callbackCount.load()
- );
+ errorCount += s_checkEnginePositions(&engine) ? 1 : 0;
usleep(SLEEP_DURATION_MSEC * 1000);
}
}
if (engine.stopAtFrame != INT32_MAX) {
callbackResult = (engine.callbackCountAfterStop == 0) ? EXIT_SUCCESS
- : EXIT_FAILURE;
+ : EXIT_FAILURE;
if (callbackResult) {
printf("ERROR - Callback count after STOP = %d\n",
engine.callbackCountAfterStop.load());
@@ -268,9 +291,7 @@
errorCount++;
}
usleep(SLEEP_DURATION_MSEC * 1000);
- printf("getFramesRead() = %d, getFramesWritten() = %d\n",
- (int32_t) AAudioStream_getFramesRead(engine.stream),
- (int32_t) AAudioStream_getFramesWritten(engine.stream));
+ errorCount += s_checkEnginePositions(&engine) ? 1 : 0;
}
s_CloseAudioStream(&engine);
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 4c762ed..896198b 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1281,6 +1281,20 @@
return aps->getMasterMono(mono);
}
+status_t AudioSystem::setMasterBalance(float balance)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setMasterBalance(balance);
+}
+
+status_t AudioSystem::getMasterBalance(float *balance)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->getMasterBalance(balance);
+}
+
float AudioSystem::getStreamVolumeDB(audio_stream_type_t stream, int index, audio_devices_t device)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index e9a0e22..c2ee2ee 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -293,6 +293,11 @@
mPreviousSchedulingGroup(SP_DEFAULT),
mPausedPosition(0)
{
+ mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
+ mAttributes.usage = AUDIO_USAGE_UNKNOWN;
+ mAttributes.flags = 0x0;
+ strcpy(mAttributes.tags, "");
+
(void)set(streamType, sampleRate, format, channelMask,
frameCount, flags, cbf, user, notificationFrames,
0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
@@ -324,6 +329,11 @@
mPausedPosition(0),
mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE)
{
+ mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
+ mAttributes.usage = AUDIO_USAGE_UNKNOWN;
+ mAttributes.flags = 0x0;
+ strcpy(mAttributes.tags, "");
+
(void)set(streamType, sampleRate, format, channelMask,
0 /*frameCount*/, flags, cbf, user, notificationFrames,
sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 00678c2..825cd4e 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -87,6 +87,8 @@
SYSTEM_READY,
FRAME_COUNT_HAL,
GET_MICROPHONES,
+ SET_MASTER_BALANCE,
+ GET_MASTER_BALANCE,
};
#define MAX_ITEMS_PER_LIST 1024
@@ -242,6 +244,34 @@
return reply.readInt32();
}
+ status_t setMasterBalance(float balance) override
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ data.writeFloat(balance);
+ status_t status = remote()->transact(SET_MASTER_BALANCE, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return reply.readInt32();
+ }
+
+ status_t getMasterBalance(float *balance) const override
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
+ status_t status = remote()->transact(GET_MASTER_BALANCE, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = (status_t)reply.readInt32();
+ if (status != NO_ERROR) {
+ return status;
+ }
+ *balance = reply.readFloat();
+ return NO_ERROR;
+ }
+
virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
@@ -1050,6 +1080,21 @@
reply->writeInt32( masterMute() );
return NO_ERROR;
} break;
+ case SET_MASTER_BALANCE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ reply->writeInt32( setMasterBalance(data.readFloat()) );
+ return NO_ERROR;
+ } break;
+ case GET_MASTER_BALANCE: {
+ CHECK_INTERFACE(IAudioFlinger, data, reply);
+ float f;
+ const status_t status = getMasterBalance(&f);
+ reply->writeInt32((int32_t)status);
+ if (status == NO_ERROR) {
+ (void)reply->writeFloat(f);
+ }
+ return NO_ERROR;
+ } break;
case SET_STREAM_VOLUME: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int stream = data.readInt32();
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 3ae7104..fbbbd11 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -80,6 +80,7 @@
MIXER_CHANNEL_MASK = 0x4006, // Channel mask for mixer output
// for haptic
HAPTIC_ENABLED = 0x4007, // Set haptic data from this track should be played or not.
+ HAPTIC_INTENSITY = 0x4008, // Set the intensity to play haptic data.
// for target RESAMPLE
SAMPLE_RATE = 0x4100, // Configure sample rate conversion on this track name;
// parameter 'value' is the new sample rate in Hz.
@@ -102,6 +103,31 @@
// parameter 'value' is a pointer to the new playback rate.
};
+ enum { // Haptic intensity, should keep consistent with VibratorService
+ HAPTIC_SCALE_VERY_LOW = -2,
+ HAPTIC_SCALE_LOW = -1,
+ HAPTIC_SCALE_NONE = 0,
+ HAPTIC_SCALE_HIGH = 1,
+ HAPTIC_SCALE_VERY_HIGH = 2,
+ };
+ typedef int32_t haptic_intensity_t;
+ static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2 / 3;
+ static constexpr float HAPTIC_SCALE_LOW_RATIO = 3 / 4;
+ static const CONSTEXPR float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;
+
+ static inline bool isValidHapticIntensity(haptic_intensity_t hapticIntensity) {
+ switch (hapticIntensity) {
+ case HAPTIC_SCALE_VERY_LOW:
+ case HAPTIC_SCALE_LOW:
+ case HAPTIC_SCALE_NONE:
+ case HAPTIC_SCALE_HIGH:
+ case HAPTIC_SCALE_VERY_HIGH:
+ return true;
+ default:
+ return false;
+ }
+ }
+
AudioMixer(size_t frameCount, uint32_t sampleRate)
: mSampleRate(sampleRate)
, mFrameCount(frameCount) {
@@ -147,6 +173,7 @@
}
}
(this->*mHook)();
+ processHapticData();
}
size_t getUnreleasedFrames(int name) const;
@@ -364,6 +391,7 @@
// Haptic
bool mHapticPlaybackEnabled;
+ haptic_intensity_t mHapticIntensity;
audio_channel_mask_t mHapticChannelMask;
uint32_t mHapticChannelCount;
audio_channel_mask_t mMixerHapticChannelMask;
@@ -374,6 +402,37 @@
uint32_t mAdjustNonDestructiveOutChannelCount;
bool mKeepContractedChannels;
+ float getHapticScaleGamma() const {
+ // Need to keep consistent with the value in VibratorService.
+ switch (mHapticIntensity) {
+ case HAPTIC_SCALE_VERY_LOW:
+ return 2.0f;
+ case HAPTIC_SCALE_LOW:
+ return 1.5f;
+ case HAPTIC_SCALE_HIGH:
+ return 0.5f;
+ case HAPTIC_SCALE_VERY_HIGH:
+ return 0.25f;
+ default:
+ return 1.0f;
+ }
+ }
+
+ float getHapticMaxAmplitudeRatio() const {
+ // Need to keep consistent with the value in VibratorService.
+ switch (mHapticIntensity) {
+ case HAPTIC_SCALE_VERY_LOW:
+ return HAPTIC_SCALE_VERY_LOW_RATIO;
+ case HAPTIC_SCALE_LOW:
+ return HAPTIC_SCALE_LOW_RATIO;
+ case HAPTIC_SCALE_NONE:
+ case HAPTIC_SCALE_HIGH:
+ case HAPTIC_SCALE_VERY_HIGH:
+ default:
+ return 1.0f;
+ }
+ }
+
private:
// hooks
void track__genericResample(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
@@ -410,6 +469,8 @@
template <int MIXTYPE, typename TO, typename TI, typename TA>
void process__noResampleOneTrack();
+ void processHapticData();
+
static process_hook_t getProcessHook(int processType, uint32_t channelCount,
audio_format_t mixerInFormat, audio_format_t mixerOutFormat);
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index ebee124..1f71844 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -719,7 +719,7 @@
private:
class MediaMetrics {
public:
- MediaMetrics() : mAnalyticsItem(new MediaAnalyticsItem("audiorecord")),
+ MediaMetrics() : mAnalyticsItem(MediaAnalyticsItem::create("audiorecord")),
mCreatedNs(systemTime(SYSTEM_TIME_REALTIME)),
mStartedNs(0), mDurationNs(0), mCount(0),
mLastError(NO_ERROR) {
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index a208602..1fb7add 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -339,6 +339,9 @@
static status_t setMasterMono(bool mono);
static status_t getMasterMono(bool *mono);
+ static status_t setMasterBalance(float balance);
+ static status_t getMasterBalance(float *balance);
+
static float getStreamVolumeDB(
audio_stream_type_t stream, int index, audio_devices_t device);
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 7fdf7cc..cbb750f 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1227,7 +1227,7 @@
private:
class MediaMetrics {
public:
- MediaMetrics() : mAnalyticsItem(new MediaAnalyticsItem("audiotrack")) {
+ MediaMetrics() : mAnalyticsItem(MediaAnalyticsItem::create("audiotrack")) {
}
~MediaMetrics() {
// mAnalyticsItem alloc failure will be flagged in the constructor
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index a34b207..ef0ed0c 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -359,6 +359,9 @@
virtual float masterVolume() const = 0;
virtual bool masterMute() const = 0;
+ virtual status_t setMasterBalance(float balance) = 0;
+ virtual status_t getMasterBalance(float *balance) const = 0;
+
/* set/get stream type state. This will probably be used by
* the preference panel, mostly.
*/
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index 2e35be6..e396cf3 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -106,7 +106,7 @@
status_t status = parametersFromHal(kvPairs, &hidlParams);
if (status != OK) return status;
return processReturn("setParameters",
- utils::setParameters(mStream, hidlParams, {} /* options */));
+ utils::setParameters(mStream, {} /* context */, hidlParams));
}
status_t StreamHalHidl::getParameters(const String8& keys, String8 *values) {
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index 86711de..86777d6 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -167,6 +167,7 @@
t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
// haptic
t->mHapticPlaybackEnabled = false;
+ t->mHapticIntensity = HAPTIC_SCALE_NONE;
t->mMixerHapticChannelMask = AUDIO_CHANNEL_NONE;
t->mMixerHapticChannelCount = 0;
t->mAdjustInChannelCount = t->channelCount + t->mHapticChannelCount;
@@ -717,6 +718,12 @@
track->prepareForAdjustChannels();
}
} break;
+ case HAPTIC_INTENSITY: {
+ const haptic_intensity_t hapticIntensity = static_cast<haptic_intensity_t>(valueInt);
+ if (track->mHapticIntensity != hapticIntensity) {
+ track->mHapticIntensity = hapticIntensity;
+ }
+ } break;
default:
LOG_ALWAYS_FATAL("setParameter track: bad param %d", param);
}
@@ -1846,6 +1853,40 @@
}
}
+void AudioMixer::processHapticData()
+{
+ // Need to keep consistent with VibrationEffect.scale(int, float, int)
+ for (const auto &pair : mGroups) {
+ // process by group of tracks with same output main buffer.
+ const auto &group = pair.second;
+ for (const int name : group) {
+ const std::shared_ptr<Track> &t = mTracks[name];
+ if (t->mHapticPlaybackEnabled) {
+ size_t sampleCount = mFrameCount * t->mMixerHapticChannelCount;
+ float gamma = t->getHapticScaleGamma();
+ float maxAmplitudeRatio = t->getHapticMaxAmplitudeRatio();
+ uint8_t* buffer = (uint8_t*)pair.first + mFrameCount * audio_bytes_per_frame(
+ t->mMixerChannelCount, t->mMixerFormat);
+ switch (t->mMixerFormat) {
+ // Mixer format should be AUDIO_FORMAT_PCM_FLOAT.
+ case AUDIO_FORMAT_PCM_FLOAT: {
+ float* fout = (float*) buffer;
+ for (size_t i = 0; i < sampleCount; i++) {
+ float mul = fout[i] >= 0 ? 1.0 : -1.0;
+ fout[i] = powf(fabsf(fout[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
+ * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * mul;
+ }
+ } break;
+ default:
+ LOG_ALWAYS_FATAL("bad mMixerFormat: %#x", t->mMixerFormat);
+ break;
+ }
+ break;
+ }
+ }
+ }
+}
+
/* This track hook is called to do resampling then mixing,
* pulling from the track's upstream AudioBufferProvider.
*
diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
index 990d260..5c6b981 100644
--- a/media/libmedia/CharacterEncodingDetector.cpp
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -28,6 +28,8 @@
#include <unicode/ucsdet.h>
#include <unicode/ustring.h>
+#include <cutils/properties.h>
+
namespace android {
CharacterEncodingDetector::CharacterEncodingDetector() {
@@ -38,6 +40,26 @@
ALOGE("could not create UConverter for UTF-8");
mUtf8Conv = NULL;
}
+
+ // Read system locale setting from system property and map to ICU encoding names.
+ mLocaleEnc = NULL;
+ char locale_value[PROPERTY_VALUE_MAX] = "";
+ if (property_get("persist.sys.locale", locale_value, NULL) > 0) {
+ const size_t len = strnlen(locale_value, sizeof(locale_value));
+
+ if (len == 3 && !strncmp(locale_value, "und", 3)) {
+ // Undetermined
+ } else if (!strncmp(locale_value, "th", 2)) { // Thai
+ mLocaleEnc = "windows-874-2000";
+ }
+ if (mLocaleEnc != NULL) {
+ ALOGV("System locale encoding = %s", mLocaleEnc);
+ } else {
+ ALOGV("Didn't recognize system locale setting, defaulting to en_US");
+ }
+ } else {
+ ALOGV("Couldn't read system locale setting, assuming en_US");
+ }
}
CharacterEncodingDetector::~CharacterEncodingDetector() {
@@ -157,7 +179,11 @@
}
}
- if (bestCombinedMatch != NULL) {
+ if (mLocaleEnc != NULL && !goodmatch && highest < 50) {
+ combinedenc = mLocaleEnc;
+ ALOGV("confidence is low but we have recognized predefined encoding, "
+ "so try this (%s) instead", mLocaleEnc);
+ } else if (bestCombinedMatch != NULL) {
combinedenc = ucsdet_getName(bestCombinedMatch, &status);
} else {
combinedenc = "ISO-8859-1";
diff --git a/media/libmedia/include/media/CharacterEncodingDetector.h b/media/libmedia/include/media/CharacterEncodingDetector.h
index deaa377..62564b1 100644
--- a/media/libmedia/include/media/CharacterEncodingDetector.h
+++ b/media/libmedia/include/media/CharacterEncodingDetector.h
@@ -54,6 +54,7 @@
StringArray mValues;
UConverter* mUtf8Conv;
+ const char* mLocaleEnc;
};
diff --git a/media/libmedia/include/media/DrmHal.h b/media/libmedia/include/media/DrmHal.h
index 7be5cf2..a630bfd 100644
--- a/media/libmedia/include/media/DrmHal.h
+++ b/media/libmedia/include/media/DrmHal.h
@@ -63,9 +63,10 @@
virtual status_t initCheck() const;
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16],
- const String8& mimeType,
- DrmPlugin::SecurityLevel level);
+ virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+ const String8& mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported);
virtual status_t createPlugin(const uint8_t uuid[16],
const String8 &appPackageName);
@@ -226,10 +227,11 @@
status_t getPropertyStringInternal(String8 const &name, String8 &value) const;
status_t getPropertyByteArrayInternal(String8 const &name,
Vector<uint8_t> &value) const;
- bool matchMimeTypeAndSecurityLevel(sp<IDrmFactory> &factory,
- const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel level);
+ status_t matchMimeTypeAndSecurityLevel(const sp<IDrmFactory> &factory,
+ const uint8_t uuid[16],
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel level,
+ bool *isSupported);
DISALLOW_EVIL_CONSTRUCTORS(DrmHal);
};
diff --git a/media/libmedia/include/media/IDrm.h b/media/libmedia/include/media/IDrm.h
index a32756f..fbe80c6 100644
--- a/media/libmedia/include/media/IDrm.h
+++ b/media/libmedia/include/media/IDrm.h
@@ -34,9 +34,10 @@
virtual status_t initCheck() const = 0;
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16],
- const String8 &mimeType,
- DrmPlugin::SecurityLevel securityLevel) = 0;
+ virtual status_t isCryptoSchemeSupported(const uint8_t uuid[16],
+ const String8 &mimeType,
+ DrmPlugin::SecurityLevel securityLevel,
+ bool *result) = 0;
virtual status_t createPlugin(const uint8_t uuid[16],
const String8 &appPackageName) = 0;
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index 2f9e7c2..4a36f6a 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -82,16 +82,19 @@
PROTO_LAST = PROTO_V1,
};
+ private:
+ // use the ::create() method instead
+ MediaAnalyticsItem();
+ MediaAnalyticsItem(Key);
+ MediaAnalyticsItem(const MediaAnalyticsItem&);
+ MediaAnalyticsItem &operator=(const MediaAnalyticsItem&);
public:
- // so clients do not need to know size details
static MediaAnalyticsItem* create(Key key);
static MediaAnalyticsItem* create();
// access functions for the class
- MediaAnalyticsItem();
- MediaAnalyticsItem(Key);
~MediaAnalyticsItem();
// SessionID ties multiple submissions for same key together
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9bcfc83..96f79e0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1906,10 +1906,16 @@
if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
return NO_INIT;
}
+ if (afSampleRate == 0) {
+ return NO_INIT;
+ }
const size_t framesPerBuffer =
(unsigned long long)sampleRate * afFrameCount / afSampleRate;
if (bufferCount == 0) {
+ if (framesPerBuffer == 0) {
+ return NO_INIT;
+ }
// use suggestedFrameCount
bufferCount = (suggestedFrameCount + framesPerBuffer - 1) / framesPerBuffer;
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f2a3038..37b13f0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -202,7 +202,7 @@
}
mAnalyticsDirty = false;
if (reinitialize) {
- mAnalyticsItem = new MediaAnalyticsItem(kKeyRecorder);
+ mAnalyticsItem = MediaAnalyticsItem::create(kKeyRecorder);
}
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index a820445..1b396c0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -97,7 +97,7 @@
mMediaClock->init();
// set up an analytics record
- mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
+ mAnalyticsItem = MediaAnalyticsItem::create(kKeyPlayer);
mLooper->start(
false, /* runOnCallingThread */
@@ -635,7 +635,7 @@
// re-init in case we prepare() and start() again.
delete mAnalyticsItem ;
- mAnalyticsItem = new MediaAnalyticsItem("nuplayer");
+ mAnalyticsItem = MediaAnalyticsItem::create("nuplayer");
if (mAnalyticsItem) {
mAnalyticsItem->setUid(mClientUid);
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index 67a0f1e..2d0c9e0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -159,9 +159,12 @@
if (drm != NULL) {
for (size_t i = 0; i < psshDRMs.size(); i++) {
DrmUUID uuid = psshDRMs[i];
- if (drm->isCryptoSchemeSupported(uuid.ptr(), String8(),
- DrmPlugin::kSecurityLevelUnknown))
+ bool isSupported = false;
+ status = drm->isCryptoSchemeSupported(uuid.ptr(), String8(),
+ DrmPlugin::kSecurityLevelUnknown, &isSupported);
+ if (status == OK && isSupported) {
supportedDRMs.add(uuid);
+ }
}
drm.clear();
diff --git a/media/libnblog/ReportPerformance.cpp b/media/libnblog/ReportPerformance.cpp
index f632e40..b050b83 100644
--- a/media/libnblog/ReportPerformance.cpp
+++ b/media/libnblog/ReportPerformance.cpp
@@ -168,7 +168,7 @@
return false;
}
- std::unique_ptr<MediaAnalyticsItem> item(new MediaAnalyticsItem("audiothread"));
+ std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("audiothread"));
const Histogram &workHist = data.workHist;
if (workHist.totalCount() > 0) {
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 03eef48..26464b8 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -77,6 +77,41 @@
},
}
+cc_library_static {
+ name: "libstagefright_mpeg2extractor",
+
+ srcs: [
+ "Utils.cpp",
+ "MediaSource.cpp",
+ "HevcUtils.cpp",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libmedia",
+ "libmedia_omx",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Wno-multichar",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
+
cc_library {
name: "libstagefright",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c7da7c7..9c58e05 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -550,7 +550,7 @@
void MediaCodec::initAnalyticsItem() {
if (mAnalyticsItem == NULL) {
- mAnalyticsItem = new MediaAnalyticsItem(kCodecKeyName);
+ mAnalyticsItem = MediaAnalyticsItem::create(kCodecKeyName);
}
mLatencyHist.setup(kLatencyHistBuckets, kLatencyHistWidth, kLatencyHistFloor);
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index 86402ce..19b174f 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -346,11 +346,13 @@
ALOGV("search for plugins at %s", libDirPath);
ALOGV("linked libs %s", gLinkedLibraries.c_str());
+ std::string libDirPathEx = libDirPath;
+ libDirPathEx += "/extractors";
android_namespace_t *extractorNs = android_create_namespace("extractor",
nullptr, // ld_library_path
- libDirPath,
+ libDirPath, // default_library_path
ANDROID_NAMESPACE_TYPE_ISOLATED,
- nullptr, // permitted_when_isolated_path
+ libDirPathEx.c_str(), // permitted_when_isolated_path
nullptr); // parent
if (!android_link_namespaces(extractorNs, nullptr, gLinkedLibraries.c_str())) {
ALOGE("Failed to link namespace. Failed to load extractor plug-ins in apex.");
@@ -361,7 +363,14 @@
.library_namespace = extractorNs,
};
- DIR *libDir = opendir(libDirPath);
+ // try extractors subfolder first
+ DIR *libDir = opendir(libDirPathEx.c_str());
+
+ if (libDir) {
+ libDirPath = libDirPathEx.c_str();
+ } else {
+ libDir = opendir(libDirPath);
+ }
if (libDir) {
struct dirent* libEntry;
while ((libEntry = readdir(libDir))) {
diff --git a/media/libstagefright/RemoteMediaExtractor.cpp b/media/libstagefright/RemoteMediaExtractor.cpp
index 9d2c42b..b0ce688 100644
--- a/media/libstagefright/RemoteMediaExtractor.cpp
+++ b/media/libstagefright/RemoteMediaExtractor.cpp
@@ -49,7 +49,7 @@
mAnalyticsItem = nullptr;
if (MEDIA_LOG) {
- mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
+ mAnalyticsItem = MediaAnalyticsItem::create(kKeyExtractor);
// track the container format (mpeg, aac, wvm, etc)
size_t ntracks = extractor->countTracks();
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index c14983a..877cb5a 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -23,6 +23,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
+#define MAX_CHANNEL_COUNT 6 /* maximum number of audio channels that can be decoded */
+
namespace android {
template<class T>
@@ -184,7 +186,7 @@
return OMX_ErrorUndefined;
}
- if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) {
+ if (pcmParams->nChannels < 1 || pcmParams->nChannels > MAX_CHANNEL_COUNT) {
return OMX_ErrorUndefined;
}
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 16179d3..4392799 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -706,6 +706,12 @@
++lineNo;
}
+ // playlist has no item, would cause exception
+ if (mItems.size() == 0) {
+ ALOGE("playlist has no item");
+ return ERROR_MALFORMED;
+ }
+
// error checking of all fields that's required to appear once
// (currently only checking "target-duration"), and
// initialization of playlist properties (eg. mTargetDurationUs)
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 325084c..c581e9d 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -261,7 +261,7 @@
return false;
}
- if (strncmp(value.c_str(), "npt=", 4)) {
+ if (strncmp(value.c_str(), "npt=", 4) && strncmp(value.c_str(), "npt:", 4)) {
return false;
}
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
new file mode 100644
index 0000000..16c7be9
--- /dev/null
+++ b/media/mediaserver/Android.bp
@@ -0,0 +1,46 @@
+
+cc_library_static {
+ name: "libregistermsext",
+ srcs: ["register.cpp"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
+
+cc_binary {
+ name: "mediaserver",
+
+ srcs: ["main_mediaserver.cpp"],
+
+ shared_libs: [
+ "libresourcemanagerservice",
+ "liblog",
+ "libmediaplayerservice",
+ "libutils",
+ "libbinder",
+ "libandroidicu",
+ "android.hardware.media.omx@1.0",
+ ],
+
+ static_libs: [
+ "libicuandroid_utils",
+ "libregistermsext",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libmediaplayerservice",
+ "frameworks/av/services/mediaresourcemanager",
+ ],
+
+ compile_multilib: "32",
+
+ init_rc: ["mediaserver.rc"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+}
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
deleted file mode 100644
index 1fbb85e..0000000
--- a/media/mediaserver/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-ifneq ($(BOARD_USE_CUSTOM_MEDIASERVEREXTENSIONS),true)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := register.cpp
-LOCAL_MODULE := libregistermsext
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Werror -Wall
-include $(BUILD_STATIC_LIBRARY)
-endif
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- main_mediaserver.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libresourcemanagerservice \
- liblog \
- libmediaplayerservice \
- libutils \
- libbinder \
- libandroidicu \
- android.hardware.media.omx@1.0 \
-
-LOCAL_STATIC_LIBRARIES := \
- libicuandroid_utils \
- libregistermsext
-
-LOCAL_C_INCLUDES := \
- frameworks/av/media/libmediaplayerservice \
- frameworks/av/services/mediaresourcemanager \
-
-LOCAL_MODULE:= mediaserver
-LOCAL_32_BIT_ONLY := true
-
-LOCAL_INIT_RC := mediaserver.rc
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 9082f62..2deb1a4 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -274,7 +274,10 @@
}
String8 mimeStr = mimeType ? String8(mimeType) : String8("");
- return drm->isCryptoSchemeSupported(uuid, mimeStr, DrmPlugin::kSecurityLevelUnknown);
+ bool isSupported = false;
+ status_t status = drm->isCryptoSchemeSupported(uuid, mimeStr,
+ DrmPlugin::kSecurityLevelUnknown, &isSupported);
+ return (status == OK) && isSupported;
}
EXPORT
diff --git a/packages/MediaComponents/apex/Android.bp b/packages/MediaComponents/apex/Android.bp
deleted file mode 100644
index d89eb77..0000000
--- a/packages/MediaComponents/apex/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-filegroup {
- name: "media_aidl",
- srcs: [
- "java/android/media/**/*.aidl",
- "java/android/service/**/*.aidl",
- ],
- exclude_srcs: [
- // Exclude these aidls to avoid errors such as
- // "Refusing to generate code with unstructured parcelables."
- "java/android/media/MediaDescription.aidl",
- "java/android/media/MediaMetadata.aidl",
- // TODO(insun): check why MediaParceledListSlice.aidl should be added here
- "java/android/media/MediaParceledListSlice.aidl",
- "java/android/media/Rating.aidl",
- "java/android/media/browse/MediaBrowser.aidl",
- "java/android/media/session/MediaSession.aidl",
- "java/android/media/session/ParcelableVolumeInfo.aidl",
- "java/android/media/session/PlaybackState.aidl",
- ],
-}
-
-java_library {
- name: "media",
- installable: true,
- sdk_version: "system_current",
- srcs: [
- "java/android/media/**/*.java",
- "java/android/service/**/*.java",
- ":media_aidl",
- ":framework-media-annotation-srcs",
- ],
- aidl: {
- local_include_dirs: ["java"],
- include_dirs: [
- "frameworks/base/core/java",
- // for android.graphics.Bitmap
- // from IMediaBrowserServiceCallback
- "frameworks/base/graphics/java",
- ],
- },
-}
diff --git a/packages/MediaComponents/apex/java/android/media/IRemoteVolumeController.aidl b/packages/MediaComponents/apex/java/android/media/IRemoteVolumeController.aidl
deleted file mode 100644
index e4a4a42..0000000
--- a/packages/MediaComponents/apex/java/android/media/IRemoteVolumeController.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.media;
-
-import android.media.session.ISessionController;
-
-/**
- * AIDL for the MediaSessionService to report interesting events on remote playback
- * to a volume control dialog. See also IVolumeController for the AudioService half.
- * TODO add in better support for multiple remote sessions.
- * @hide
- */
-oneway interface IRemoteVolumeController {
- void remoteVolumeChanged(ISessionController session, int flags);
- // sets the default session to use with the slider, replaces remoteSliderVisibility
- // on IVolumeController
- void updateRemoteController(ISessionController session);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/ISessionTokensListener.aidl b/packages/MediaComponents/apex/java/android/media/ISessionTokensListener.aidl
deleted file mode 100644
index c83a19e..0000000
--- a/packages/MediaComponents/apex/java/android/media/ISessionTokensListener.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.
- */
-
-package android.media;
-
-import android.os.Bundle;
-
-/**
- * Listens for changes to the list of session tokens.
- * @hide
- */
-oneway interface ISessionTokensListener {
- void onSessionTokensChanged(in List<Bundle> tokens);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/MediaDescription.aidl b/packages/MediaComponents/apex/java/android/media/MediaDescription.aidl
deleted file mode 100644
index 6f934f7..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaDescription.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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.
-*/
-
-package android.media;
-
-parcelable MediaDescription;
diff --git a/packages/MediaComponents/apex/java/android/media/MediaDescription.java b/packages/MediaComponents/apex/java/android/media/MediaDescription.java
deleted file mode 100644
index 31079e5..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaDescription.java
+++ /dev/null
@@ -1,383 +0,0 @@
-package android.media;
-
-import android.annotation.Nullable;
-import android.graphics.Bitmap;
-import android.media.browse.MediaBrowser;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-/**
- * A simple set of metadata for a media item suitable for display. This can be
- * created using the Builder or retrieved from existing metadata using
- * {@link MediaMetadata#getDescription()}.
- */
-public class MediaDescription implements Parcelable {
- /**
- * A unique persistent id for the content or null.
- */
- private final String mMediaId;
- /**
- * A primary title suitable for display or null.
- */
- private final CharSequence mTitle;
- /**
- * A subtitle suitable for display or null.
- */
- private final CharSequence mSubtitle;
- /**
- * A description suitable for display or null.
- */
- private final CharSequence mDescription;
- /**
- * A bitmap icon suitable for display or null.
- */
- private final Bitmap mIcon;
- /**
- * A Uri for an icon suitable for display or null.
- */
- private final Uri mIconUri;
- /**
- * Extras for opaque use by apps/system.
- */
- private final Bundle mExtras;
- /**
- * A Uri to identify this content.
- */
- private final Uri mMediaUri;
-
- /**
- * Used as a long extra field to indicate the bluetooth folder type of the media item as
- * specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5. This is valid only for
- * {@link MediaBrowser.MediaItem} with {@link MediaBrowser.MediaItem#FLAG_BROWSABLE}. The value
- * should be one of the following:
- * <ul>
- * <li>{@link #BT_FOLDER_TYPE_MIXED}</li>
- * <li>{@link #BT_FOLDER_TYPE_TITLES}</li>
- * <li>{@link #BT_FOLDER_TYPE_ALBUMS}</li>
- * <li>{@link #BT_FOLDER_TYPE_ARTISTS}</li>
- * <li>{@link #BT_FOLDER_TYPE_GENRES}</li>
- * <li>{@link #BT_FOLDER_TYPE_PLAYLISTS}</li>
- * <li>{@link #BT_FOLDER_TYPE_YEARS}</li>
- * </ul>
- *
- * @see #getExtras()
- */
- public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
-
- /**
- * The type of folder that is unknown or contains media elements of mixed types as specified in
- * the section 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_MIXED = 0;
-
- /**
- * The type of folder that contains media elements only as specified in the section 6.10.2.2 of
- * the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_TITLES = 1;
-
- /**
- * The type of folder that contains folders categorized by album as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_ALBUMS = 2;
-
- /**
- * The type of folder that contains folders categorized by artist as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_ARTISTS = 3;
-
- /**
- * The type of folder that contains folders categorized by genre as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_GENRES = 4;
-
- /**
- * The type of folder that contains folders categorized by playlist as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_PLAYLISTS = 5;
-
- /**
- * The type of folder that contains folders categorized by year as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_YEARS = 6;
-
- private MediaDescription(String mediaId, CharSequence title, CharSequence subtitle,
- CharSequence description, Bitmap icon, Uri iconUri, Bundle extras, Uri mediaUri) {
- mMediaId = mediaId;
- mTitle = title;
- mSubtitle = subtitle;
- mDescription = description;
- mIcon = icon;
- mIconUri = iconUri;
- mExtras = extras;
- mMediaUri = mediaUri;
- }
-
- private MediaDescription(Parcel in) {
- mMediaId = in.readString();
- mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mIcon = in.readParcelable(null);
- mIconUri = in.readParcelable(null);
- mExtras = in.readBundle();
- mMediaUri = in.readParcelable(null);
- }
-
- /**
- * Returns the media id or null. See
- * {@link MediaMetadata#METADATA_KEY_MEDIA_ID}.
- */
- public @Nullable String getMediaId() {
- return mMediaId;
- }
-
- /**
- * Returns a title suitable for display or null.
- *
- * @return A title or null.
- */
- public @Nullable CharSequence getTitle() {
- return mTitle;
- }
-
- /**
- * Returns a subtitle suitable for display or null.
- *
- * @return A subtitle or null.
- */
- public @Nullable CharSequence getSubtitle() {
- return mSubtitle;
- }
-
- /**
- * Returns a description suitable for display or null.
- *
- * @return A description or null.
- */
- public @Nullable CharSequence getDescription() {
- return mDescription;
- }
-
- /**
- * Returns a bitmap icon suitable for display or null.
- *
- * @return An icon or null.
- */
- public @Nullable Bitmap getIconBitmap() {
- return mIcon;
- }
-
- /**
- * Returns a Uri for an icon suitable for display or null.
- *
- * @return An icon uri or null.
- */
- public @Nullable Uri getIconUri() {
- return mIconUri;
- }
-
- /**
- * Returns any extras that were added to the description.
- *
- * @return A bundle of extras or null.
- */
- public @Nullable Bundle getExtras() {
- return mExtras;
- }
-
- /**
- * Returns a Uri representing this content or null.
- *
- * @return A media Uri or null.
- */
- public @Nullable Uri getMediaUri() {
- return mMediaUri;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mMediaId);
- TextUtils.writeToParcel(mTitle, dest, 0);
- TextUtils.writeToParcel(mSubtitle, dest, 0);
- TextUtils.writeToParcel(mDescription, dest, 0);
- dest.writeParcelable(mIcon, flags);
- dest.writeParcelable(mIconUri, flags);
- dest.writeBundle(mExtras);
- dest.writeParcelable(mMediaUri, flags);
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == null) {
- return false;
- }
-
- if (!(o instanceof MediaDescription)){
- return false;
- }
-
- final MediaDescription d = (MediaDescription) o;
-
- if (!String.valueOf(mTitle).equals(String.valueOf(d.mTitle))) {
- return false;
- }
-
- if (!String.valueOf(mSubtitle).equals(String.valueOf(d.mSubtitle))) {
- return false;
- }
-
- if (!String.valueOf(mDescription).equals(String.valueOf(d.mDescription))) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public String toString() {
- return mTitle + ", " + mSubtitle + ", " + mDescription;
- }
-
- public static final Parcelable.Creator<MediaDescription> CREATOR =
- new Parcelable.Creator<MediaDescription>() {
- @Override
- public MediaDescription createFromParcel(Parcel in) {
- return new MediaDescription(in);
- }
-
- @Override
- public MediaDescription[] newArray(int size) {
- return new MediaDescription[size];
- }
- };
-
- /**
- * Builder for {@link MediaDescription} objects.
- */
- public static class Builder {
- private String mMediaId;
- private CharSequence mTitle;
- private CharSequence mSubtitle;
- private CharSequence mDescription;
- private Bitmap mIcon;
- private Uri mIconUri;
- private Bundle mExtras;
- private Uri mMediaUri;
-
- /**
- * Creates an initially empty builder.
- */
- public Builder() {
- }
-
- /**
- * Sets the media id.
- *
- * @param mediaId The unique id for the item or null.
- * @return this
- */
- public Builder setMediaId(@Nullable String mediaId) {
- mMediaId = mediaId;
- return this;
- }
-
- /**
- * Sets the title.
- *
- * @param title A title suitable for display to the user or null.
- * @return this
- */
- public Builder setTitle(@Nullable CharSequence title) {
- mTitle = title;
- return this;
- }
-
- /**
- * Sets the subtitle.
- *
- * @param subtitle A subtitle suitable for display to the user or null.
- * @return this
- */
- public Builder setSubtitle(@Nullable CharSequence subtitle) {
- mSubtitle = subtitle;
- return this;
- }
-
- /**
- * Sets the description.
- *
- * @param description A description suitable for display to the user or
- * null.
- * @return this
- */
- public Builder setDescription(@Nullable CharSequence description) {
- mDescription = description;
- return this;
- }
-
- /**
- * Sets the icon.
- *
- * @param icon A {@link Bitmap} icon suitable for display to the user or
- * null.
- * @return this
- */
- public Builder setIconBitmap(@Nullable Bitmap icon) {
- mIcon = icon;
- return this;
- }
-
- /**
- * Sets the icon uri.
- *
- * @param iconUri A {@link Uri} for an icon suitable for display to the
- * user or null.
- * @return this
- */
- public Builder setIconUri(@Nullable Uri iconUri) {
- mIconUri = iconUri;
- return this;
- }
-
- /**
- * Sets a bundle of extras.
- *
- * @param extras The extras to include with this description or null.
- * @return this
- */
- public Builder setExtras(@Nullable Bundle extras) {
- mExtras = extras;
- return this;
- }
-
- /**
- * Sets the media uri.
- *
- * @param mediaUri The content's {@link Uri} for the item or null.
- * @return this
- */
- public Builder setMediaUri(@Nullable Uri mediaUri) {
- mMediaUri = mediaUri;
- return this;
- }
-
- public MediaDescription build() {
- return new MediaDescription(mMediaId, mTitle, mSubtitle, mDescription, mIcon, mIconUri,
- mExtras, mMediaUri);
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/MediaMetadata.aidl b/packages/MediaComponents/apex/java/android/media/MediaMetadata.aidl
deleted file mode 100644
index 66ee483..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaMetadata.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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.
-*/
-
-package android.media;
-
-parcelable MediaMetadata;
diff --git a/packages/MediaComponents/apex/java/android/media/MediaMetadata.java b/packages/MediaComponents/apex/java/android/media/MediaMetadata.java
deleted file mode 100644
index adfd20b..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaMetadata.java
+++ /dev/null
@@ -1,941 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-package android.media;
-
-import android.annotation.NonNull;
-import android.annotation.StringDef;
-import android.annotation.UnsupportedAppUsage;
-import android.content.ContentResolver;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.media.browse.MediaBrowser;
-import android.media.session.MediaController;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
-import java.util.Objects;
-
-/**
- * Contains metadata about an item, such as the title, artist, etc.
- */
-public final class MediaMetadata implements Parcelable {
- private static final String TAG = "MediaMetadata";
-
- /**
- * @hide
- */
- @StringDef(prefix = { "METADATA_KEY_" }, value = {
- METADATA_KEY_TITLE,
- METADATA_KEY_ARTIST,
- METADATA_KEY_ALBUM,
- METADATA_KEY_AUTHOR,
- METADATA_KEY_WRITER,
- METADATA_KEY_COMPOSER,
- METADATA_KEY_COMPILATION,
- METADATA_KEY_DATE,
- METADATA_KEY_GENRE,
- METADATA_KEY_ALBUM_ARTIST,
- METADATA_KEY_ART_URI,
- METADATA_KEY_ALBUM_ART_URI,
- METADATA_KEY_DISPLAY_TITLE,
- METADATA_KEY_DISPLAY_SUBTITLE,
- METADATA_KEY_DISPLAY_DESCRIPTION,
- METADATA_KEY_DISPLAY_ICON_URI,
- METADATA_KEY_MEDIA_ID,
- METADATA_KEY_MEDIA_URI,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface TextKey {}
-
- /**
- * @hide
- */
- @StringDef(prefix = { "METADATA_KEY_" }, value = {
- METADATA_KEY_DURATION,
- METADATA_KEY_YEAR,
- METADATA_KEY_TRACK_NUMBER,
- METADATA_KEY_NUM_TRACKS,
- METADATA_KEY_DISC_NUMBER,
- METADATA_KEY_BT_FOLDER_TYPE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LongKey {}
-
- /**
- * @hide
- */
- @StringDef(prefix = { "METADATA_KEY_" }, value = {
- METADATA_KEY_ART,
- METADATA_KEY_ALBUM_ART,
- METADATA_KEY_DISPLAY_ICON,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface BitmapKey {}
-
- /**
- * @hide
- */
- @StringDef(prefix = { "METADATA_KEY_" }, value = {
- METADATA_KEY_USER_RATING,
- METADATA_KEY_RATING,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface RatingKey {}
-
- /**
- * The title of the media.
- */
- public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-
- /**
- * The artist of the media.
- */
- public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-
- /**
- * The duration of the media in ms. A negative duration indicates that the
- * duration is unknown (or infinite).
- */
- public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-
- /**
- * The album title for the media.
- */
- public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-
- /**
- * The author of the media.
- */
- public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-
- /**
- * The writer of the media.
- */
- public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-
- /**
- * The composer of the media.
- */
- public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-
- /**
- * The compilation status of the media.
- */
- public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-
- /**
- * The date the media was created or published. The format is unspecified
- * but RFC 3339 is recommended.
- */
- public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
-
- /**
- * The year the media was created or published as a long.
- */
- public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
-
- /**
- * The genre of the media.
- */
- public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-
- /**
- * The track number for the media.
- */
- public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-
- /**
- * The number of tracks in the media's original source.
- */
- public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
-
- /**
- * The disc number for the media's original source.
- */
- public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-
- /**
- * The artist for the album of the media's original source.
- */
- public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-
- /**
- * The artwork for the media as a {@link Bitmap}.
- * <p>
- * The artwork should be relatively small and may be scaled down by the
- * system if it is too large. For higher resolution artwork
- * {@link #METADATA_KEY_ART_URI} should be used instead.
- */
- public static final String METADATA_KEY_ART = "android.media.metadata.ART";
-
- /**
- * The artwork for the media as a Uri formatted String. The artwork can be
- * loaded using a combination of {@link ContentResolver#openInputStream} and
- * {@link BitmapFactory#decodeStream}.
- * <p>
- * For the best results, Uris should use the content:// style and support
- * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
- * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
- */
- public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
-
- /**
- * The artwork for the album of the media's original source as a
- * {@link Bitmap}.
- * <p>
- * The artwork should be relatively small and may be scaled down by the
- * system if it is too large. For higher resolution artwork
- * {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead.
- */
- public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
-
- /**
- * The artwork for the album of the media's original source as a Uri
- * formatted String. The artwork can be loaded using a combination of
- * {@link ContentResolver#openInputStream} and
- * {@link BitmapFactory#decodeStream}.
- * <p>
- * For the best results, Uris should use the content:// style and support
- * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
- * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
- */
- public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
-
- /**
- * The user's rating for the media.
- *
- * @see Rating
- */
- public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-
- /**
- * The overall rating for the media.
- *
- * @see Rating
- */
- public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
-
- /**
- * A title that is suitable for display to the user. This will generally be
- * the same as {@link #METADATA_KEY_TITLE} but may differ for some formats.
- * When displaying media described by this metadata this should be preferred
- * if present.
- */
- public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
-
- /**
- * A subtitle that is suitable for display to the user. When displaying a
- * second line for media described by this metadata this should be preferred
- * to other fields if present.
- */
- public static final String METADATA_KEY_DISPLAY_SUBTITLE
- = "android.media.metadata.DISPLAY_SUBTITLE";
-
- /**
- * A description that is suitable for display to the user. When displaying
- * more information for media described by this metadata this should be
- * preferred to other fields if present.
- */
- public static final String METADATA_KEY_DISPLAY_DESCRIPTION
- = "android.media.metadata.DISPLAY_DESCRIPTION";
-
- /**
- * An icon or thumbnail that is suitable for display to the user. When
- * displaying an icon for media described by this metadata this should be
- * preferred to other fields if present. This must be a {@link Bitmap}.
- * <p>
- * The icon should be relatively small and may be scaled down by the system
- * if it is too large. For higher resolution artwork
- * {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead.
- */
- public static final String METADATA_KEY_DISPLAY_ICON
- = "android.media.metadata.DISPLAY_ICON";
-
- /**
- * A Uri formatted String for an icon or thumbnail that is suitable for
- * display to the user. When displaying more information for media described
- * by this metadata the display description should be preferred to other
- * fields when present. The icon can be loaded using a combination of
- * {@link ContentResolver#openInputStream} and
- * {@link BitmapFactory#decodeStream}.
- * <p>
- * For the best results, Uris should use the content:// style and support
- * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
- * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
- */
- public static final String METADATA_KEY_DISPLAY_ICON_URI
- = "android.media.metadata.DISPLAY_ICON_URI";
-
- /**
- * A String key for identifying the content. This value is specific to the
- * service providing the content. If used, this should be a persistent
- * unique key for the underlying content. It may be used with
- * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
- * to initiate playback when provided by a {@link MediaBrowser} connected to
- * the same app.
- */
- public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
-
- /**
- * A Uri formatted String representing the content. This value is specific to the
- * service providing the content. It may be used with
- * {@link MediaController.TransportControls#playFromUri(Uri, Bundle)}
- * to initiate playback when provided by a {@link MediaBrowser} connected to
- * the same app.
- */
- public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
-
- /**
- * The bluetooth folder type of the media specified in the section 6.10.2.2 of the Bluetooth
- * AVRCP 1.5. It should be one of the following:
- * <ul>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_MIXED}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_TITLES}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_ALBUMS}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_ARTISTS}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_GENRES}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_PLAYLISTS}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_YEARS}</li>
- * </ul>
- */
- public static final String METADATA_KEY_BT_FOLDER_TYPE
- = "android.media.metadata.BT_FOLDER_TYPE";
-
- private static final @TextKey String[] PREFERRED_DESCRIPTION_ORDER = {
- METADATA_KEY_TITLE,
- METADATA_KEY_ARTIST,
- METADATA_KEY_ALBUM,
- METADATA_KEY_ALBUM_ARTIST,
- METADATA_KEY_WRITER,
- METADATA_KEY_AUTHOR,
- METADATA_KEY_COMPOSER
- };
-
- private static final @BitmapKey String[] PREFERRED_BITMAP_ORDER = {
- METADATA_KEY_DISPLAY_ICON,
- METADATA_KEY_ART,
- METADATA_KEY_ALBUM_ART
- };
-
- private static final @TextKey String[] PREFERRED_URI_ORDER = {
- METADATA_KEY_DISPLAY_ICON_URI,
- METADATA_KEY_ART_URI,
- METADATA_KEY_ALBUM_ART_URI
- };
-
- private static final int METADATA_TYPE_INVALID = -1;
- private static final int METADATA_TYPE_LONG = 0;
- private static final int METADATA_TYPE_TEXT = 1;
- private static final int METADATA_TYPE_BITMAP = 2;
- private static final int METADATA_TYPE_RATING = 3;
- private static final ArrayMap<String, Integer> METADATA_KEYS_TYPE;
-
- static {
- METADATA_KEYS_TYPE = new ArrayMap<String, Integer>();
- METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
- METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_BT_FOLDER_TYPE, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
- }
-
- private static final SparseArray<String> EDITOR_KEY_MAPPING;
-
- static {
- EDITOR_KEY_MAPPING = new SparseArray<String>();
- EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART);
- EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING);
- EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
- METADATA_KEY_ALBUM_ARTIST);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
- METADATA_KEY_TRACK_NUMBER);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
- METADATA_KEY_COMPILATION);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
- METADATA_KEY_DISC_NUMBER);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
- METADATA_KEY_NUM_TRACKS);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR);
- }
-
- private final Bundle mBundle;
- private MediaDescription mDescription;
-
- private MediaMetadata(Bundle bundle) {
- mBundle = new Bundle(bundle);
- }
-
- private MediaMetadata(Parcel in) {
- mBundle = in.readBundle();
- }
-
- /**
- * Returns true if the given key is contained in the metadata
- *
- * @param key a String key
- * @return true if the key exists in this metadata, false otherwise
- */
- public boolean containsKey(String key) {
- return mBundle.containsKey(key);
- }
-
- /**
- * Returns the value associated with the given key, or null if no mapping of
- * the desired type exists for the given key or a null value is explicitly
- * associated with the key.
- *
- * @param key The key the value is stored under
- * @return a CharSequence value, or null
- */
- public CharSequence getText(@TextKey String key) {
- return mBundle.getCharSequence(key);
- }
-
- /**
- * Returns the text value associated with the given key as a String, or null
- * if no mapping of the desired type exists for the given key or a null
- * value is explicitly associated with the key. This is equivalent to
- * calling {@link #getText getText().toString()} if the value is not null.
- *
- * @param key The key the value is stored under
- * @return a String value, or null
- */
- public String getString(@TextKey String key) {
- CharSequence text = getText(key);
- if (text != null) {
- return text.toString();
- }
- return null;
- }
-
- /**
- * Returns the value associated with the given key, or 0L if no long exists
- * for the given key.
- *
- * @param key The key the value is stored under
- * @return a long value
- */
- public long getLong(@LongKey String key) {
- return mBundle.getLong(key, 0);
- }
-
- /**
- * Returns a {@link Rating} for the given key or null if no rating exists
- * for the given key.
- *
- * @param key The key the value is stored under
- * @return A {@link Rating} or null
- */
- public Rating getRating(@RatingKey String key) {
- Rating rating = null;
- try {
- rating = mBundle.getParcelable(key);
- } catch (Exception e) {
- // ignore, value was not a bitmap
- Log.w(TAG, "Failed to retrieve a key as Rating.", e);
- }
- return rating;
- }
-
- /**
- * Returns a {@link Bitmap} for the given key or null if no bitmap exists
- * for the given key.
- *
- * @param key The key the value is stored under
- * @return A {@link Bitmap} or null
- */
- public Bitmap getBitmap(@BitmapKey String key) {
- Bitmap bmp = null;
- try {
- bmp = mBundle.getParcelable(key);
- } catch (Exception e) {
- // ignore, value was not a bitmap
- Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
- }
- return bmp;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeBundle(mBundle);
- }
-
- /**
- * Returns the number of fields in this metadata.
- *
- * @return The number of fields in the metadata.
- */
- public int size() {
- return mBundle.size();
- }
-
- /**
- * Returns a Set containing the Strings used as keys in this metadata.
- *
- * @return a Set of String keys
- */
- public Set<String> keySet() {
- return mBundle.keySet();
- }
-
- /**
- * Returns a simple description of this metadata for display purposes.
- *
- * @return A simple description of this metadata.
- */
- public @NonNull MediaDescription getDescription() {
- if (mDescription != null) {
- return mDescription;
- }
-
- String mediaId = getString(METADATA_KEY_MEDIA_ID);
-
- CharSequence[] text = new CharSequence[3];
- Bitmap icon = null;
- Uri iconUri = null;
-
- // First handle the case where display data is set already
- CharSequence displayText = getText(METADATA_KEY_DISPLAY_TITLE);
- if (!TextUtils.isEmpty(displayText)) {
- // If they have a display title use only display data, otherwise use
- // our best bets
- text[0] = displayText;
- text[1] = getText(METADATA_KEY_DISPLAY_SUBTITLE);
- text[2] = getText(METADATA_KEY_DISPLAY_DESCRIPTION);
- } else {
- // Use whatever fields we can
- int textIndex = 0;
- int keyIndex = 0;
- while (textIndex < text.length && keyIndex < PREFERRED_DESCRIPTION_ORDER.length) {
- CharSequence next = getText(PREFERRED_DESCRIPTION_ORDER[keyIndex++]);
- if (!TextUtils.isEmpty(next)) {
- // Fill in the next empty bit of text
- text[textIndex++] = next;
- }
- }
- }
-
- // Get the best art bitmap we can find
- for (int i = 0; i < PREFERRED_BITMAP_ORDER.length; i++) {
- Bitmap next = getBitmap(PREFERRED_BITMAP_ORDER[i]);
- if (next != null) {
- icon = next;
- break;
- }
- }
-
- // Get the best Uri we can find
- for (int i = 0; i < PREFERRED_URI_ORDER.length; i++) {
- String next = getString(PREFERRED_URI_ORDER[i]);
- if (!TextUtils.isEmpty(next)) {
- iconUri = Uri.parse(next);
- break;
- }
- }
-
- Uri mediaUri = null;
- String mediaUriStr = getString(METADATA_KEY_MEDIA_URI);
- if (!TextUtils.isEmpty(mediaUriStr)) {
- mediaUri = Uri.parse(mediaUriStr);
- }
-
- MediaDescription.Builder bob = new MediaDescription.Builder();
- bob.setMediaId(mediaId);
- bob.setTitle(text[0]);
- bob.setSubtitle(text[1]);
- bob.setDescription(text[2]);
- bob.setIconBitmap(icon);
- bob.setIconUri(iconUri);
- bob.setMediaUri(mediaUri);
- if (mBundle.containsKey(METADATA_KEY_BT_FOLDER_TYPE)) {
- Bundle bundle = new Bundle();
- bundle.putLong(MediaDescription.EXTRA_BT_FOLDER_TYPE,
- getLong(METADATA_KEY_BT_FOLDER_TYPE));
- bob.setExtras(bundle);
- }
- mDescription = bob.build();
-
- return mDescription;
- }
-
- /**
- * Helper for getting the String key used by {@link MediaMetadata} from the
- * integer key that {@link MediaMetadataEditor} uses.
- *
- * @param editorKey The key used by the editor
- * @return The key used by this class or null if no mapping exists
- * @hide
- */
- @UnsupportedAppUsage
- public static String getKeyFromMetadataEditorKey(int editorKey) {
- return EDITOR_KEY_MAPPING.get(editorKey, null);
- }
-
- public static final Parcelable.Creator<MediaMetadata> CREATOR =
- new Parcelable.Creator<MediaMetadata>() {
- @Override
- public MediaMetadata createFromParcel(Parcel in) {
- return new MediaMetadata(in);
- }
-
- @Override
- public MediaMetadata[] newArray(int size) {
- return new MediaMetadata[size];
- }
- };
-
- /**
- * Compares the contents of this object to another MediaMetadata object. It
- * does not compare Bitmaps and Ratings as the media player can choose to
- * forgo these fields depending on how you retrieve the MediaMetadata.
- *
- * @param o The Metadata object to compare this object against
- * @return Whether or not the two objects have matching fields (excluding
- * Bitmaps and Ratings)
- */
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
-
- if (!(o instanceof MediaMetadata)) {
- return false;
- }
-
- final MediaMetadata m = (MediaMetadata) o;
-
- for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
- String key = METADATA_KEYS_TYPE.keyAt(i);
- switch (METADATA_KEYS_TYPE.valueAt(i)) {
- case METADATA_TYPE_TEXT:
- if (!Objects.equals(getString(key), m.getString(key))) {
- return false;
- }
- break;
- case METADATA_TYPE_LONG:
- if (getLong(key) != m.getLong(key)) {
- return false;
- }
- break;
- default:
- // Ignore ratings and bitmaps when comparing
- break;
- }
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int hashCode = 17;
-
- for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
- String key = METADATA_KEYS_TYPE.keyAt(i);
- switch (METADATA_KEYS_TYPE.valueAt(i)) {
- case METADATA_TYPE_TEXT:
- hashCode = 31 * hashCode + Objects.hash(getString(key));
- break;
- case METADATA_TYPE_LONG:
- hashCode = 31 * hashCode + Long.hashCode(getLong(key));
- break;
- default:
- // Ignore ratings and bitmaps when comparing
- break;
- }
- }
-
- return hashCode;
- }
-
- /**
- * Use to build MediaMetadata objects. The system defined metadata keys must
- * use the appropriate data type.
- */
- public static final class Builder {
- private final Bundle mBundle;
-
- /**
- * Create an empty Builder. Any field that should be included in the
- * {@link MediaMetadata} must be added.
- */
- public Builder() {
- mBundle = new Bundle();
- }
-
- /**
- * Create a Builder using a {@link MediaMetadata} instance to set the
- * initial values. All fields in the source metadata will be included in
- * the new metadata. Fields can be overwritten by adding the same key.
- *
- * @param source
- */
- public Builder(MediaMetadata source) {
- mBundle = new Bundle(source.mBundle);
- }
-
- /**
- * Create a Builder using a {@link MediaMetadata} instance to set
- * initial values, but replace bitmaps with a scaled down copy if they
- * are larger than maxBitmapSize.
- *
- * @param source The original metadata to copy.
- * @param maxBitmapSize The maximum height/width for bitmaps contained
- * in the metadata.
- * @hide
- */
- public Builder(MediaMetadata source, int maxBitmapSize) {
- this(source);
- for (String key : mBundle.keySet()) {
- Object value = mBundle.get(key);
- if (value != null && value instanceof Bitmap) {
- Bitmap bmp = (Bitmap) value;
- if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
- putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
- }
- }
- }
- }
-
- /**
- * Put a CharSequence value into the metadata. Custom keys may be used,
- * but if the METADATA_KEYs defined in this class are used they may only
- * be one of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_TITLE}</li>
- * <li>{@link #METADATA_KEY_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ALBUM}</li>
- * <li>{@link #METADATA_KEY_AUTHOR}</li>
- * <li>{@link #METADATA_KEY_WRITER}</li>
- * <li>{@link #METADATA_KEY_COMPOSER}</li>
- * <li>{@link #METADATA_KEY_DATE}</li>
- * <li>{@link #METADATA_KEY_GENRE}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ART_URI}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The CharSequence value to store
- * @return The Builder to allow chaining
- */
- public Builder putText(@TextKey String key, CharSequence value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a CharSequence");
- }
- }
- mBundle.putCharSequence(key, value);
- return this;
- }
-
- /**
- * Put a String value into the metadata. Custom keys may be used, but if
- * the METADATA_KEYs defined in this class are used they may only be one
- * of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_TITLE}</li>
- * <li>{@link #METADATA_KEY_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ALBUM}</li>
- * <li>{@link #METADATA_KEY_AUTHOR}</li>
- * <li>{@link #METADATA_KEY_WRITER}</li>
- * <li>{@link #METADATA_KEY_COMPOSER}</li>
- * <li>{@link #METADATA_KEY_DATE}</li>
- * <li>{@link #METADATA_KEY_GENRE}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ART_URI}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
- * </ul>
- * <p>
- * Uris for artwork should use the content:// style and support
- * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork
- * through {@link ContentResolver#openTypedAssetFileDescriptor(Uri,
- * String, Bundle)}.
- *
- * @param key The key for referencing this value
- * @param value The String value to store
- * @return The Builder to allow chaining
- */
- public Builder putString(@TextKey String key, String value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a String");
- }
- }
- mBundle.putCharSequence(key, value);
- return this;
- }
-
- /**
- * Put a long value into the metadata. Custom keys may be used, but if
- * the METADATA_KEYs defined in this class are used they may only be one
- * of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_DURATION}</li>
- * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
- * <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
- * <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
- * <li>{@link #METADATA_KEY_YEAR}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The long value to store
- * @return The Builder to allow chaining
- */
- public Builder putLong(@LongKey String key, long value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a long");
- }
- }
- mBundle.putLong(key, value);
- return this;
- }
-
- /**
- * Put a {@link Rating} into the metadata. Custom keys may be used, but
- * if the METADATA_KEYs defined in this class are used they may only be
- * one of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_RATING}</li>
- * <li>{@link #METADATA_KEY_USER_RATING}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The Rating value to store
- * @return The Builder to allow chaining
- */
- public Builder putRating(@RatingKey String key, Rating value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a Rating");
- }
- }
- mBundle.putParcelable(key, value);
- return this;
- }
-
- /**
- * Put a {@link Bitmap} into the metadata. Custom keys may be used, but
- * if the METADATA_KEYs defined in this class are used they may only be
- * one of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_ART}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ART}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
- * </ul>
- * <p>
- * Large bitmaps may be scaled down by the system when
- * {@link android.media.session.MediaSession#setMetadata} is called.
- * To pass full resolution images {@link Uri Uris} should be used with
- * {@link #putString}.
- *
- * @param key The key for referencing this value
- * @param value The Bitmap to store
- * @return The Builder to allow chaining
- */
- public Builder putBitmap(@BitmapKey String key, Bitmap value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a Bitmap");
- }
- }
- mBundle.putParcelable(key, value);
- return this;
- }
-
- /**
- * Creates a {@link MediaMetadata} instance with the specified fields.
- *
- * @return The new MediaMetadata instance
- */
- public MediaMetadata build() {
- return new MediaMetadata(mBundle);
- }
-
- private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
- float maxSizeF = maxSize;
- float widthScale = maxSizeF / bmp.getWidth();
- float heightScale = maxSizeF / bmp.getHeight();
- float scale = Math.min(widthScale, heightScale);
- int height = (int) (bmp.getHeight() * scale);
- int width = (int) (bmp.getWidth() * scale);
- return Bitmap.createScaledBitmap(bmp, width, height, true);
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.aidl b/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.aidl
deleted file mode 100644
index 228ea9c..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 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.
- */
-
-package android.media;
-
-/** @hide */
-parcelable MediaParceledListSlice;
\ No newline at end of file
diff --git a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.java b/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.java
deleted file mode 100644
index ec3fdb7..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * 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.
- */
-
-package android.media;
-
-import android.annotation.UnsupportedAppUsage;
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Transfer a large list of objects across an IPC. Splits into multiple transactions if needed.
- * Note: Only use classes declared final in order to avoid subclasses overriding reading/writing
- * parcel logic.
- *
- * TODO: Add test for sending large data
- * @hide
- */
-public class MediaParceledListSlice<T extends Parcelable> implements Parcelable {
- private static final String TAG = "MediaParceledListSlice";
- private static final boolean DEBUG = false;
-
- private static final int MAX_IPC_SIZE = 64 * 1024; // IBinder.MAX_IPC_SIZE
-
- final List<T> mList;
-
- public MediaParceledListSlice(List<T> list) {
- if (list == null) {
- throw new IllegalArgumentException("list shouldn't be null");
- }
- mList = list;
- }
-
- MediaParceledListSlice(Parcel p) {
- final int itemCount = p.readInt();
- mList = new ArrayList<>(itemCount);
- if (DEBUG) {
- Log.d(TAG, "Retrieving " + itemCount + " items");
- }
- if (itemCount <= 0) {
- return;
- }
-
- int i = 0;
- while (i < itemCount) {
- if (p.readInt() == 0) {
- break;
- }
-
- final T parcelable = p.readParcelable(null);
- mList.add(parcelable);
-
- if (DEBUG) {
- Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size() - 1));
- }
- i++;
- }
- if (i >= itemCount) {
- return;
- }
- final IBinder retriever = p.readStrongBinder();
- while (i < itemCount) {
- if (DEBUG) {
- Log.d(TAG, "Reading more @" + i + " of " + itemCount + ": retriever=" + retriever);
- }
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInt(i);
- try {
- retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failure retrieving array; only received " + i + " of " + itemCount, e);
- return;
- }
- while (i < itemCount && reply.readInt() != 0) {
- final T parcelable = reply.readParcelable(null);
- mList.add(parcelable);
-
- if (DEBUG) {
- Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size() - 1));
- }
- i++;
- }
- reply.recycle();
- data.recycle();
- }
- }
-
- public List<T> getList() {
- return mList;
- }
-
- /**
- * Write this to another Parcel. Note that this discards the internal Parcel
- * and should not be used anymore. This is so we can pass this to a Binder
- * where we won't have a chance to call recycle on this.
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- final int itemCount = mList.size();
- dest.writeInt(itemCount);
- if (DEBUG) {
- Log.d(TAG, "Writing " + itemCount + " items");
- }
- if (itemCount > 0) {
- int i = 0;
- while (i < itemCount && dest.dataSize() < MAX_IPC_SIZE) {
- dest.writeInt(1);
-
- final T parcelable = mList.get(i);
- dest.writeParcelable(parcelable, flags);
-
- if (DEBUG) {
- Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
- }
- i++;
- }
- if (i < itemCount) {
- dest.writeInt(0);
- Binder retriever = new Binder() {
- @Override
- protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- if (code != FIRST_CALL_TRANSACTION) {
- return super.onTransact(code, data, reply, flags);
- }
- int i = data.readInt();
- if (DEBUG) {
- Log.d(TAG, "Writing more @" + i + " of " + itemCount);
- }
- while (i < itemCount && reply.dataSize() < MAX_IPC_SIZE) {
- reply.writeInt(1);
-
- final T parcelable = mList.get(i);
- reply.writeParcelable(parcelable, flags);
-
- if (DEBUG) {
- Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
- }
- i++;
- }
- if (i < itemCount) {
- if (DEBUG) {
- Log.d(TAG, "Breaking @" + i + " of " + itemCount);
- }
- reply.writeInt(0);
- }
- return true;
- }
- };
- if (DEBUG) {
- Log.d(TAG, "Breaking @" + i + " of " + itemCount + ": retriever=" + retriever);
- }
- dest.writeStrongBinder(retriever);
- }
- }
- }
-
- @Override
- public int describeContents() {
- int contents = 0;
- final List<T> list = getList();
- for (int i = 0; i < list.size(); i++) {
- contents |= list.get(i).describeContents();
- }
- return contents;
- }
-
- public static final Parcelable.Creator<MediaParceledListSlice> CREATOR =
- new Parcelable.Creator<MediaParceledListSlice>() {
- @Override
- public MediaParceledListSlice createFromParcel(Parcel in) {
- return new MediaParceledListSlice(in);
- }
-
- @Override
- public MediaParceledListSlice[] newArray(int size) {
- return new MediaParceledListSlice[size];
- }
- };
-}
diff --git a/packages/MediaComponents/apex/java/android/media/Rating.aidl b/packages/MediaComponents/apex/java/android/media/Rating.aidl
deleted file mode 100644
index 1dc336a..0000000
--- a/packages/MediaComponents/apex/java/android/media/Rating.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package android.media;
-
-parcelable Rating;
diff --git a/packages/MediaComponents/apex/java/android/media/Rating.java b/packages/MediaComponents/apex/java/android/media/Rating.java
deleted file mode 100644
index 04d5364..0000000
--- a/packages/MediaComponents/apex/java/android/media/Rating.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-package android.media;
-
-import android.annotation.IntDef;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A class to encapsulate rating information used as content metadata.
- * A rating is defined by its rating style (see {@link #RATING_HEART},
- * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
- * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
- * be defined as "unrated"), both of which are defined when the rating instance is constructed
- * through one of the factory methods.
- */
-public final class Rating implements Parcelable {
- private final static String TAG = "Rating";
-
- /**
- * @hide
- */
- @IntDef({RATING_NONE, RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS,
- RATING_5_STARS, RATING_PERCENTAGE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface Style {}
-
- /**
- * @hide
- */
- @IntDef({RATING_3_STARS, RATING_4_STARS, RATING_5_STARS})
- @Retention(RetentionPolicy.SOURCE)
- public @interface StarStyle {}
-
- /**
- * Indicates a rating style is not supported. A Rating will never have this
- * type, but can be used by other classes to indicate they do not support
- * Rating.
- */
- public final static int RATING_NONE = 0;
-
- /**
- * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
- * indicate the content referred to is a favorite (or not).
- */
- public final static int RATING_HEART = 1;
-
- /**
- * A rating style for "thumb up" vs "thumb down".
- */
- public final static int RATING_THUMB_UP_DOWN = 2;
-
- /**
- * A rating style with 0 to 3 stars.
- */
- public final static int RATING_3_STARS = 3;
-
- /**
- * A rating style with 0 to 4 stars.
- */
- public final static int RATING_4_STARS = 4;
-
- /**
- * A rating style with 0 to 5 stars.
- */
- public final static int RATING_5_STARS = 5;
-
- /**
- * A rating style expressed as a percentage.
- */
- public final static int RATING_PERCENTAGE = 6;
-
- private final static float RATING_NOT_RATED = -1.0f;
-
- private final int mRatingStyle;
-
- private final float mRatingValue;
-
- private Rating(@Style int ratingStyle, float rating) {
- mRatingStyle = ratingStyle;
- mRatingValue = rating;
- }
-
- @Override
- public String toString() {
- return "Rating:style=" + mRatingStyle + " rating="
- + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue));
- }
-
- @Override
- public int describeContents() {
- return mRatingStyle;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mRatingStyle);
- dest.writeFloat(mRatingValue);
- }
-
- public static final Parcelable.Creator<Rating> CREATOR
- = new Parcelable.Creator<Rating>() {
- /**
- * Rebuilds a Rating previously stored with writeToParcel().
- * @param p Parcel object to read the Rating from
- * @return a new Rating created from the data in the parcel
- */
- @Override
- public Rating createFromParcel(Parcel p) {
- return new Rating(p.readInt(), p.readFloat());
- }
-
- @Override
- public Rating[] newArray(int size) {
- return new Rating[size];
- }
- };
-
- /**
- * Return a Rating instance with no rating.
- * Create and return a new Rating instance with no rating known for the given
- * rating style.
- * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
- * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
- * or {@link #RATING_PERCENTAGE}.
- * @return null if an invalid rating style is passed, a new Rating instance otherwise.
- */
- public static Rating newUnratedRating(@Style int ratingStyle) {
- switch(ratingStyle) {
- case RATING_HEART:
- case RATING_THUMB_UP_DOWN:
- case RATING_3_STARS:
- case RATING_4_STARS:
- case RATING_5_STARS:
- case RATING_PERCENTAGE:
- return new Rating(ratingStyle, RATING_NOT_RATED);
- default:
- return null;
- }
- }
-
- /**
- * Return a Rating instance with a heart-based rating.
- * Create and return a new Rating instance with a rating style of {@link #RATING_HEART},
- * and a heart-based rating.
- * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
- * @return a new Rating instance.
- */
- public static Rating newHeartRating(boolean hasHeart) {
- return new Rating(RATING_HEART, hasHeart ? 1.0f : 0.0f);
- }
-
- /**
- * Return a Rating instance with a thumb-based rating.
- * Create and return a new Rating instance with a {@link #RATING_THUMB_UP_DOWN}
- * rating style, and a "thumb up" or "thumb down" rating.
- * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
- * @return a new Rating instance.
- */
- public static Rating newThumbRating(boolean thumbIsUp) {
- return new Rating(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f);
- }
-
- /**
- * Return a Rating instance with a star-based rating.
- * Create and return a new Rating instance with one of the star-base rating styles
- * and the given integer or fractional number of stars. Non integer values can for instance
- * be used to represent an average rating value, which might not be an integer number of stars.
- * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
- * {@link #RATING_5_STARS}.
- * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
- * the rating style.
- * @return null if the rating style is invalid, or the rating is out of range,
- * a new Rating instance otherwise.
- */
- public static Rating newStarRating(@StarStyle int starRatingStyle, float starRating) {
- float maxRating = -1.0f;
- switch(starRatingStyle) {
- case RATING_3_STARS:
- maxRating = 3.0f;
- break;
- case RATING_4_STARS:
- maxRating = 4.0f;
- break;
- case RATING_5_STARS:
- maxRating = 5.0f;
- break;
- default:
- Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
- return null;
- }
- if ((starRating < 0.0f) || (starRating > maxRating)) {
- Log.e(TAG, "Trying to set out of range star-based rating");
- return null;
- }
- return new Rating(starRatingStyle, starRating);
- }
-
- /**
- * Return a Rating instance with a percentage-based rating.
- * Create and return a new Rating instance with a {@link #RATING_PERCENTAGE}
- * rating style, and a rating of the given percentage.
- * @param percent the value of the rating
- * @return null if the rating is out of range, a new Rating instance otherwise.
- */
- public static Rating newPercentageRating(float percent) {
- if ((percent < 0.0f) || (percent > 100.0f)) {
- Log.e(TAG, "Invalid percentage-based rating value");
- return null;
- } else {
- return new Rating(RATING_PERCENTAGE, percent);
- }
- }
-
- /**
- * Return whether there is a rating value available.
- * @return true if the instance was not created with {@link #newUnratedRating(int)}.
- */
- public boolean isRated() {
- return mRatingValue >= 0.0f;
- }
-
- /**
- * Return the rating style.
- * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
- * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
- * or {@link #RATING_PERCENTAGE}.
- */
- @Style
- public int getRatingStyle() {
- return mRatingStyle;
- }
-
- /**
- * Return whether the rating is "heart selected".
- * @return true if the rating is "heart selected", false if the rating is "heart unselected",
- * if the rating style is not {@link #RATING_HEART} or if it is unrated.
- */
- public boolean hasHeart() {
- if (mRatingStyle != RATING_HEART) {
- return false;
- } else {
- return (mRatingValue == 1.0f);
- }
- }
-
- /**
- * Return whether the rating is "thumb up".
- * @return true if the rating is "thumb up", false if the rating is "thumb down",
- * if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated.
- */
- public boolean isThumbUp() {
- if (mRatingStyle != RATING_THUMB_UP_DOWN) {
- return false;
- } else {
- return (mRatingValue == 1.0f);
- }
- }
-
- /**
- * Return the star-based rating value.
- * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
- * not star-based, or if it is unrated.
- */
- public float getStarRating() {
- switch (mRatingStyle) {
- case RATING_3_STARS:
- case RATING_4_STARS:
- case RATING_5_STARS:
- if (isRated()) {
- return mRatingValue;
- }
- default:
- return -1.0f;
- }
- }
-
- /**
- * Return the percentage-based rating value.
- * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
- * not percentage-based, or if it is unrated.
- */
- public float getPercentRating() {
- if ((mRatingStyle != RATING_PERCENTAGE) || !isRated()) {
- return -1.0f;
- } else {
- return mRatingValue;
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/VolumeProvider.java b/packages/MediaComponents/apex/java/android/media/VolumeProvider.java
deleted file mode 100644
index 1c017c5..0000000
--- a/packages/MediaComponents/apex/java/android/media/VolumeProvider.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-package android.media;
-
-import android.annotation.IntDef;
-import android.media.session.MediaSession;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Handles requests to adjust or set the volume on a session. This is also used
- * to push volume updates back to the session. The provider must call
- * {@link #setCurrentVolume(int)} each time the volume being provided changes.
- * <p>
- * You can set a volume provider on a session by calling
- * {@link MediaSession#setPlaybackToRemote}.
- */
-public abstract class VolumeProvider {
-
- /**
- * @hide
- */
- @IntDef({VOLUME_CONTROL_FIXED, VOLUME_CONTROL_RELATIVE, VOLUME_CONTROL_ABSOLUTE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ControlType {}
-
- /**
- * The volume is fixed and can not be modified. Requests to change volume
- * should be ignored.
- */
- public static final int VOLUME_CONTROL_FIXED = 0;
-
- /**
- * The volume control uses relative adjustment via
- * {@link #onAdjustVolume(int)}. Attempts to set the volume to a specific
- * value should be ignored.
- */
- public static final int VOLUME_CONTROL_RELATIVE = 1;
-
- /**
- * The volume control uses an absolute value. It may be adjusted using
- * {@link #onAdjustVolume(int)} or set directly using
- * {@link #onSetVolumeTo(int)}.
- */
- public static final int VOLUME_CONTROL_ABSOLUTE = 2;
-
- private final int mControlType;
- private final int mMaxVolume;
- private int mCurrentVolume;
- private Callback mCallback;
-
- /**
- * Create a new volume provider for handling volume events. You must specify
- * the type of volume control, the maximum volume that can be used, and the
- * current volume on the output.
- *
- * @param volumeControl The method for controlling volume that is used by
- * this provider.
- * @param maxVolume The maximum allowed volume.
- * @param currentVolume The current volume on the output.
- */
- public VolumeProvider(@ControlType int volumeControl, int maxVolume, int currentVolume) {
- mControlType = volumeControl;
- mMaxVolume = maxVolume;
- mCurrentVolume = currentVolume;
- }
-
- /**
- * Get the volume control type that this volume provider uses.
- *
- * @return The volume control type for this volume provider
- */
- @ControlType
- public final int getVolumeControl() {
- return mControlType;
- }
-
- /**
- * Get the maximum volume this provider allows.
- *
- * @return The max allowed volume.
- */
- public final int getMaxVolume() {
- return mMaxVolume;
- }
-
- /**
- * Gets the current volume. This will be the last value set by
- * {@link #setCurrentVolume(int)}.
- *
- * @return The current volume.
- */
- public final int getCurrentVolume() {
- return mCurrentVolume;
- }
-
- /**
- * Notify the system that the current volume has been changed. This must be
- * called every time the volume changes to ensure it is displayed properly.
- *
- * @param currentVolume The current volume on the output.
- */
- public final void setCurrentVolume(int currentVolume) {
- mCurrentVolume = currentVolume;
- if (mCallback != null) {
- mCallback.onVolumeChanged(this);
- }
- }
-
- /**
- * Override to handle requests to set the volume of the current output.
- * After the volume has been modified {@link #setCurrentVolume} must be
- * called to notify the system.
- *
- * @param volume The volume to set the output to.
- */
- public void onSetVolumeTo(int volume) {
- }
-
- /**
- * Override to handle requests to adjust the volume of the current output.
- * Direction will be one of {@link AudioManager#ADJUST_LOWER},
- * {@link AudioManager#ADJUST_RAISE}, {@link AudioManager#ADJUST_SAME}.
- * After the volume has been modified {@link #setCurrentVolume} must be
- * called to notify the system.
- *
- * @param direction The direction to change the volume in.
- */
- public void onAdjustVolume(int direction) {
- }
-
- /**
- * Sets a callback to receive volume changes.
- * @hide
- */
- public void setCallback(Callback callback) {
- mCallback = callback;
- }
-
- /**
- * Listens for changes to the volume.
- * @hide
- */
- public static abstract class Callback {
- public abstract void onVolumeChanged(VolumeProvider volumeProvider);
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.aidl b/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.aidl
deleted file mode 100644
index 782e094..0000000
--- a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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.
-*/
-
-package android.media.browse;
-
-parcelable MediaBrowser.MediaItem;
\ No newline at end of file
diff --git a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.java b/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.java
deleted file mode 100644
index b1b14c6..0000000
--- a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.java
+++ /dev/null
@@ -1,1171 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.media.browse;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.media.MediaDescription;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.service.media.IMediaBrowserService;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.service.media.MediaBrowserService;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map.Entry;
-
-/**
- * Browses media content offered by a link MediaBrowserService.
- * <p>
- * This object is not thread-safe. All calls should happen on the thread on which the browser
- * was constructed.
- * </p>
- * <h3>Standard Extra Data</h3>
- *
- * <p>These are the current standard fields that can be used as extra data via
- * {@link #subscribe(String, Bundle, SubscriptionCallback)},
- * {@link #unsubscribe(String, SubscriptionCallback)}, and
- * {@link SubscriptionCallback#onChildrenLoaded(String, List, Bundle)}.
- *
- * <ul>
- * <li> {@link #EXTRA_PAGE}
- * <li> {@link #EXTRA_PAGE_SIZE}
- * </ul>
- */
-public final class MediaBrowser {
- private static final String TAG = "MediaBrowser";
- private static final boolean DBG = false;
-
- /**
- * Used as an int extra field to denote the page number to subscribe.
- * The value of {@code EXTRA_PAGE} should be greater than or equal to 0.
- *
- * @see #EXTRA_PAGE_SIZE
- */
- public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
-
- /**
- * Used as an int extra field to denote the number of media items in a page.
- * The value of {@code EXTRA_PAGE_SIZE} should be greater than or equal to 1.
- *
- * @see #EXTRA_PAGE
- */
- public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
-
- private static final int CONNECT_STATE_DISCONNECTING = 0;
- private static final int CONNECT_STATE_DISCONNECTED = 1;
- private static final int CONNECT_STATE_CONNECTING = 2;
- private static final int CONNECT_STATE_CONNECTED = 3;
- private static final int CONNECT_STATE_SUSPENDED = 4;
-
- private final Context mContext;
- private final ComponentName mServiceComponent;
- private final ConnectionCallback mCallback;
- private final Bundle mRootHints;
- private final Handler mHandler = new Handler();
- private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
-
- private volatile int mState = CONNECT_STATE_DISCONNECTED;
- private volatile String mRootId;
- private volatile MediaSession.Token mMediaSessionToken;
- private volatile Bundle mExtras;
-
- private MediaServiceConnection mServiceConnection;
- private IMediaBrowserService mServiceBinder;
- private IMediaBrowserServiceCallbacks mServiceCallbacks;
-
- /**
- * Creates a media browser for the specified media browser service.
- *
- * @param context The context.
- * @param serviceComponent The component name of the media browser service.
- * @param callback The connection callback.
- * @param rootHints An optional bundle of service-specific arguments to send
- * to the media browser service when connecting and retrieving the root id
- * for browsing, or null if none. The contents of this bundle may affect
- * the information returned when browsing.
- * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_RECENT
- * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
- * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
- */
- public MediaBrowser(Context context, ComponentName serviceComponent,
- ConnectionCallback callback, Bundle rootHints) {
- if (context == null) {
- throw new IllegalArgumentException("context must not be null");
- }
- if (serviceComponent == null) {
- throw new IllegalArgumentException("service component must not be null");
- }
- if (callback == null) {
- throw new IllegalArgumentException("connection callback must not be null");
- }
- mContext = context;
- mServiceComponent = serviceComponent;
- mCallback = callback;
- mRootHints = rootHints == null ? null : new Bundle(rootHints);
- }
-
- /**
- * Connects to the media browser service.
- * <p>
- * The connection callback specified in the constructor will be invoked
- * when the connection completes or fails.
- * </p>
- */
- public void connect() {
- if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
- throw new IllegalStateException("connect() called while neither disconnecting nor "
- + "disconnected (state=" + getStateLabel(mState) + ")");
- }
-
- mState = CONNECT_STATE_CONNECTING;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mState == CONNECT_STATE_DISCONNECTING) {
- return;
- }
- mState = CONNECT_STATE_CONNECTING;
- // TODO: remove this extra check.
- if (DBG) {
- if (mServiceConnection != null) {
- throw new RuntimeException("mServiceConnection should be null. Instead it"
- + " is " + mServiceConnection);
- }
- }
- if (mServiceBinder != null) {
- throw new RuntimeException("mServiceBinder should be null. Instead it is "
- + mServiceBinder);
- }
- if (mServiceCallbacks != null) {
- throw new RuntimeException("mServiceCallbacks should be null. Instead it is "
- + mServiceCallbacks);
- }
-
- final Intent intent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
- intent.setComponent(mServiceComponent);
-
- mServiceConnection = new MediaServiceConnection();
-
- boolean bound = false;
- try {
- bound = mContext.bindService(intent, mServiceConnection,
- Context.BIND_AUTO_CREATE);
- } catch (Exception ex) {
- Log.e(TAG, "Failed binding to service " + mServiceComponent);
- }
-
- if (!bound) {
- // Tell them that it didn't work.
- forceCloseConnection();
- mCallback.onConnectionFailed();
- }
-
- if (DBG) {
- Log.d(TAG, "connect...");
- dump();
- }
- }
- });
- }
-
- /**
- * Disconnects from the media browser service.
- * After this, no more callbacks will be received.
- */
- public void disconnect() {
- // It's ok to call this any state, because allowing this lets apps not have
- // to check isConnected() unnecessarily. They won't appreciate the extra
- // assertions for this. We do everything we can here to go back to a sane state.
- mState = CONNECT_STATE_DISCONNECTING;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // connect() could be called before this. Then we will disconnect and reconnect.
- if (mServiceCallbacks != null) {
- try {
- mServiceBinder.disconnect(mServiceCallbacks);
- } catch (RemoteException ex) {
- // We are disconnecting anyway. Log, just for posterity but it's not
- // a big problem.
- Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
- }
- }
- int state = mState;
- forceCloseConnection();
- // If the state was not CONNECT_STATE_DISCONNECTING, keep the state so that
- // the operation came after disconnect() can be handled properly.
- if (state != CONNECT_STATE_DISCONNECTING) {
- mState = state;
- }
- if (DBG) {
- Log.d(TAG, "disconnect...");
- dump();
- }
- }
- });
- }
-
- /**
- * Null out the variables and unbind from the service. This doesn't include
- * calling disconnect on the service, because we only try to do that in the
- * clean shutdown cases.
- * <p>
- * Everywhere that calls this EXCEPT for disconnect() should follow it with
- * a call to mCallback.onConnectionFailed(). Disconnect doesn't do that callback
- * for a clean shutdown, but everywhere else is a dirty shutdown and should
- * notify the app.
- * <p>
- * Also, mState should be updated properly. Mostly it should be CONNECT_STATE_DIACONNECTED
- * except for disconnect().
- */
- private void forceCloseConnection() {
- if (mServiceConnection != null) {
- try {
- mContext.unbindService(mServiceConnection);
- } catch (IllegalArgumentException e) {
- if (DBG) {
- Log.d(TAG, "unbindService failed", e);
- }
- }
- }
- mState = CONNECT_STATE_DISCONNECTED;
- mServiceConnection = null;
- mServiceBinder = null;
- mServiceCallbacks = null;
- mRootId = null;
- mMediaSessionToken = null;
- }
-
- /**
- * Returns whether the browser is connected to the service.
- */
- public boolean isConnected() {
- return mState == CONNECT_STATE_CONNECTED;
- }
-
- /**
- * Gets the service component that the media browser is connected to.
- */
- public @NonNull ComponentName getServiceComponent() {
- if (!isConnected()) {
- throw new IllegalStateException("getServiceComponent() called while not connected" +
- " (state=" + mState + ")");
- }
- return mServiceComponent;
- }
-
- /**
- * Gets the root id.
- * <p>
- * Note that the root id may become invalid or change when the
- * browser is disconnected.
- * </p>
- *
- * @throws IllegalStateException if not connected.
- */
- public @NonNull String getRoot() {
- if (!isConnected()) {
- throw new IllegalStateException("getRoot() called while not connected (state="
- + getStateLabel(mState) + ")");
- }
- return mRootId;
- }
-
- /**
- * Gets any extras for the media service.
- *
- * @throws IllegalStateException if not connected.
- */
- public @Nullable Bundle getExtras() {
- if (!isConnected()) {
- throw new IllegalStateException("getExtras() called while not connected (state="
- + getStateLabel(mState) + ")");
- }
- return mExtras;
- }
-
- /**
- * Gets the media session token associated with the media browser.
- * <p>
- * Note that the session token may become invalid or change when the
- * browser is disconnected.
- * </p>
- *
- * @return The session token for the browser, never null.
- *
- * @throws IllegalStateException if not connected.
- */
- public @NonNull MediaSession.Token getSessionToken() {
- if (!isConnected()) {
- throw new IllegalStateException("getSessionToken() called while not connected (state="
- + mState + ")");
- }
- return mMediaSessionToken;
- }
-
- /**
- * Queries for information about the media items that are contained within
- * the specified id and subscribes to receive updates when they change.
- * <p>
- * The list of subscriptions is maintained even when not connected and is
- * restored after the reconnection. It is ok to subscribe while not connected
- * but the results will not be returned until the connection completes.
- * </p>
- * <p>
- * If the id is already subscribed with a different callback then the new
- * callback will replace the previous one and the child data will be
- * reloaded.
- * </p>
- *
- * @param parentId The id of the parent media item whose list of children
- * will be subscribed.
- * @param callback The callback to receive the list of children.
- */
- public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
- subscribeInternal(parentId, null, callback);
- }
-
- /**
- * Queries with service-specific arguments for information about the media items
- * that are contained within the specified id and subscribes to receive updates
- * when they change.
- * <p>
- * The list of subscriptions is maintained even when not connected and is
- * restored after the reconnection. It is ok to subscribe while not connected
- * but the results will not be returned until the connection completes.
- * </p>
- * <p>
- * If the id is already subscribed with a different callback then the new
- * callback will replace the previous one and the child data will be
- * reloaded.
- * </p>
- *
- * @param parentId The id of the parent media item whose list of children
- * will be subscribed.
- * @param options The bundle of service-specific arguments to send to the media
- * browser service. The contents of this bundle may affect the
- * information returned when browsing.
- * @param callback The callback to receive the list of children.
- */
- public void subscribe(@NonNull String parentId, @NonNull Bundle options,
- @NonNull SubscriptionCallback callback) {
- if (options == null) {
- throw new IllegalArgumentException("options cannot be null");
- }
- subscribeInternal(parentId, new Bundle(options), callback);
- }
-
- /**
- * Unsubscribes for changes to the children of the specified media id.
- * <p>
- * The query callback will no longer be invoked for results associated with
- * this id once this method returns.
- * </p>
- *
- * @param parentId The id of the parent media item whose list of children
- * will be unsubscribed.
- */
- public void unsubscribe(@NonNull String parentId) {
- unsubscribeInternal(parentId, null);
- }
-
- /**
- * Unsubscribes for changes to the children of the specified media id through a callback.
- * <p>
- * The query callback will no longer be invoked for results associated with
- * this id once this method returns.
- * </p>
- *
- * @param parentId The id of the parent media item whose list of children
- * will be unsubscribed.
- * @param callback A callback sent to the media browser service to subscribe.
- */
- public void unsubscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("callback cannot be null");
- }
- unsubscribeInternal(parentId, callback);
- }
-
- /**
- * Retrieves a specific {@link MediaItem} from the connected service. Not
- * all services may support this, so falling back to subscribing to the
- * parent's id should be used when unavailable.
- *
- * @param mediaId The id of the item to retrieve.
- * @param cb The callback to receive the result on.
- */
- public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
- if (TextUtils.isEmpty(mediaId)) {
- throw new IllegalArgumentException("mediaId cannot be empty.");
- }
- if (cb == null) {
- throw new IllegalArgumentException("cb cannot be null.");
- }
- if (mState != CONNECT_STATE_CONNECTED) {
- Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- cb.onError(mediaId);
- }
- });
- return;
- }
- ResultReceiver receiver = new ResultReceiver(mHandler) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (!isConnected()) {
- return;
- }
- if (resultCode != 0 || resultData == null
- || !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
- cb.onError(mediaId);
- return;
- }
- Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
- if (item != null && !(item instanceof MediaItem)) {
- cb.onError(mediaId);
- return;
- }
- cb.onItemLoaded((MediaItem)item);
- }
- };
- try {
- mServiceBinder.getMediaItem(mediaId, receiver, mServiceCallbacks);
- } catch (RemoteException e) {
- Log.i(TAG, "Remote error getting media item.");
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- cb.onError(mediaId);
- }
- });
- }
- }
-
- private void subscribeInternal(String parentId, Bundle options, SubscriptionCallback callback) {
- // Check arguments.
- if (TextUtils.isEmpty(parentId)) {
- throw new IllegalArgumentException("parentId cannot be empty.");
- }
- if (callback == null) {
- throw new IllegalArgumentException("callback cannot be null");
- }
- // Update or create the subscription.
- Subscription sub = mSubscriptions.get(parentId);
- if (sub == null) {
- sub = new Subscription();
- mSubscriptions.put(parentId, sub);
- }
- sub.putCallback(mContext, options, callback);
-
- // If we are connected, tell the service that we are watching. If we aren't connected,
- // the service will be told when we connect.
- if (isConnected()) {
- try {
- if (options == null) {
- mServiceBinder.addSubscriptionDeprecated(parentId, mServiceCallbacks);
- }
- mServiceBinder.addSubscription(parentId, callback.mToken, options,
- mServiceCallbacks);
- } catch (RemoteException ex) {
- // Process is crashing. We will disconnect, and upon reconnect we will
- // automatically reregister. So nothing to do here.
- Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
- }
- }
- }
-
- private void unsubscribeInternal(String parentId, SubscriptionCallback callback) {
- // Check arguments.
- if (TextUtils.isEmpty(parentId)) {
- throw new IllegalArgumentException("parentId cannot be empty.");
- }
-
- Subscription sub = mSubscriptions.get(parentId);
- if (sub == null) {
- return;
- }
- // Tell the service if necessary.
- try {
- if (callback == null) {
- if (isConnected()) {
- mServiceBinder.removeSubscriptionDeprecated(parentId, mServiceCallbacks);
- mServiceBinder.removeSubscription(parentId, null, mServiceCallbacks);
- }
- } else {
- final List<SubscriptionCallback> callbacks = sub.getCallbacks();
- final List<Bundle> optionsList = sub.getOptionsList();
- for (int i = callbacks.size() - 1; i >= 0; --i) {
- if (callbacks.get(i) == callback) {
- if (isConnected()) {
- mServiceBinder.removeSubscription(
- parentId, callback.mToken, mServiceCallbacks);
- }
- callbacks.remove(i);
- optionsList.remove(i);
- }
- }
- }
- } catch (RemoteException ex) {
- // Process is crashing. We will disconnect, and upon reconnect we will
- // automatically reregister. So nothing to do here.
- Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
- }
-
- if (sub.isEmpty() || callback == null) {
- mSubscriptions.remove(parentId);
- }
- }
-
- /**
- * For debugging.
- */
- private static String getStateLabel(int state) {
- switch (state) {
- case CONNECT_STATE_DISCONNECTING:
- return "CONNECT_STATE_DISCONNECTING";
- case CONNECT_STATE_DISCONNECTED:
- return "CONNECT_STATE_DISCONNECTED";
- case CONNECT_STATE_CONNECTING:
- return "CONNECT_STATE_CONNECTING";
- case CONNECT_STATE_CONNECTED:
- return "CONNECT_STATE_CONNECTED";
- case CONNECT_STATE_SUSPENDED:
- return "CONNECT_STATE_SUSPENDED";
- default:
- return "UNKNOWN/" + state;
- }
- }
-
- private final void onServiceConnected(final IMediaBrowserServiceCallbacks callback,
- final String root, final MediaSession.Token session, final Bundle extra) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // Check to make sure there hasn't been a disconnect or a different
- // ServiceConnection.
- if (!isCurrent(callback, "onConnect")) {
- return;
- }
- // Don't allow them to call us twice.
- if (mState != CONNECT_STATE_CONNECTING) {
- Log.w(TAG, "onConnect from service while mState="
- + getStateLabel(mState) + "... ignoring");
- return;
- }
- mRootId = root;
- mMediaSessionToken = session;
- mExtras = extra;
- mState = CONNECT_STATE_CONNECTED;
-
- if (DBG) {
- Log.d(TAG, "ServiceCallbacks.onConnect...");
- dump();
- }
- mCallback.onConnected();
-
- // we may receive some subscriptions before we are connected, so re-subscribe
- // everything now
- for (Entry<String, Subscription> subscriptionEntry : mSubscriptions.entrySet()) {
- String id = subscriptionEntry.getKey();
- Subscription sub = subscriptionEntry.getValue();
- List<SubscriptionCallback> callbackList = sub.getCallbacks();
- List<Bundle> optionsList = sub.getOptionsList();
- for (int i = 0; i < callbackList.size(); ++i) {
- try {
- mServiceBinder.addSubscription(id, callbackList.get(i).mToken,
- optionsList.get(i), mServiceCallbacks);
- } catch (RemoteException ex) {
- // Process is crashing. We will disconnect, and upon reconnect we will
- // automatically reregister. So nothing to do here.
- Log.d(TAG, "addSubscription failed with RemoteException parentId="
- + id);
- }
- }
- }
- }
- });
- }
-
- private final void onConnectionFailed(final IMediaBrowserServiceCallbacks callback) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Log.e(TAG, "onConnectFailed for " + mServiceComponent);
-
- // Check to make sure there hasn't been a disconnect or a different
- // ServiceConnection.
- if (!isCurrent(callback, "onConnectFailed")) {
- return;
- }
- // Don't allow them to call us twice.
- if (mState != CONNECT_STATE_CONNECTING) {
- Log.w(TAG, "onConnect from service while mState="
- + getStateLabel(mState) + "... ignoring");
- return;
- }
-
- // Clean up
- forceCloseConnection();
-
- // Tell the app.
- mCallback.onConnectionFailed();
- }
- });
- }
-
- private final void onLoadChildren(final IMediaBrowserServiceCallbacks callback,
- final String parentId, final MediaParceledListSlice list, final Bundle options) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // Check that there hasn't been a disconnect or a different
- // ServiceConnection.
- if (!isCurrent(callback, "onLoadChildren")) {
- return;
- }
-
- if (DBG) {
- Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
- }
-
- // Check that the subscription is still subscribed.
- final Subscription subscription = mSubscriptions.get(parentId);
- if (subscription != null) {
- // Tell the app.
- SubscriptionCallback subscriptionCallback =
- subscription.getCallback(mContext, options);
- if (subscriptionCallback != null) {
- List<MediaItem> data = list == null ? null : list.getList();
- if (options == null) {
- if (data == null) {
- subscriptionCallback.onError(parentId);
- } else {
- subscriptionCallback.onChildrenLoaded(parentId, data);
- }
- } else {
- if (data == null) {
- subscriptionCallback.onError(parentId, options);
- } else {
- subscriptionCallback.onChildrenLoaded(parentId, data, options);
- }
- }
- return;
- }
- }
- if (DBG) {
- Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
- }
- }
- });
- }
-
- /**
- * Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not.
- */
- private boolean isCurrent(IMediaBrowserServiceCallbacks callback, String funcName) {
- if (mServiceCallbacks != callback || mState == CONNECT_STATE_DISCONNECTING
- || mState == CONNECT_STATE_DISCONNECTED) {
- if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
- Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
- + mServiceCallbacks + " this=" + this);
- }
- return false;
- }
- return true;
- }
-
- private ServiceCallbacks getNewServiceCallbacks() {
- return new ServiceCallbacks(this);
- }
-
- /**
- * Log internal state.
- * @hide
- */
- void dump() {
- Log.d(TAG, "MediaBrowser...");
- Log.d(TAG, " mServiceComponent=" + mServiceComponent);
- Log.d(TAG, " mCallback=" + mCallback);
- Log.d(TAG, " mRootHints=" + mRootHints);
- Log.d(TAG, " mState=" + getStateLabel(mState));
- Log.d(TAG, " mServiceConnection=" + mServiceConnection);
- Log.d(TAG, " mServiceBinder=" + mServiceBinder);
- Log.d(TAG, " mServiceCallbacks=" + mServiceCallbacks);
- Log.d(TAG, " mRootId=" + mRootId);
- Log.d(TAG, " mMediaSessionToken=" + mMediaSessionToken);
- }
-
- /**
- * A class with information on a single media item for use in browsing/searching media.
- * MediaItems are application dependent so we cannot guarantee that they contain the
- * right values.
- */
- public static class MediaItem implements Parcelable {
- private final int mFlags;
- private final MediaDescription mDescription;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
- public @interface Flags { }
-
- /**
- * Flag: Indicates that the item has children of its own.
- */
- public static final int FLAG_BROWSABLE = 1 << 0;
-
- /**
- * Flag: Indicates that the item is playable.
- * <p>
- * The id of this item may be passed to
- * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
- * to start playing it.
- * </p>
- */
- public static final int FLAG_PLAYABLE = 1 << 1;
-
- /**
- * Create a new MediaItem for use in browsing media.
- * @param description The description of the media, which must include a
- * media id.
- * @param flags The flags for this item.
- */
- public MediaItem(@NonNull MediaDescription description, @Flags int flags) {
- if (description == null) {
- throw new IllegalArgumentException("description cannot be null");
- }
- if (TextUtils.isEmpty(description.getMediaId())) {
- throw new IllegalArgumentException("description must have a non-empty media id");
- }
- mFlags = flags;
- mDescription = description;
- }
-
- /**
- * Private constructor.
- */
- private MediaItem(Parcel in) {
- mFlags = in.readInt();
- mDescription = MediaDescription.CREATOR.createFromParcel(in);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mFlags);
- mDescription.writeToParcel(out, flags);
- }
-
- @Override
- public String toString() {
- final StringBuilder sb = new StringBuilder("MediaItem{");
- sb.append("mFlags=").append(mFlags);
- sb.append(", mDescription=").append(mDescription);
- sb.append('}');
- return sb.toString();
- }
-
- public static final Parcelable.Creator<MediaItem> CREATOR =
- new Parcelable.Creator<MediaItem>() {
- @Override
- public MediaItem createFromParcel(Parcel in) {
- return new MediaItem(in);
- }
-
- @Override
- public MediaItem[] newArray(int size) {
- return new MediaItem[size];
- }
- };
-
- /**
- * Gets the flags of the item.
- */
- public @Flags int getFlags() {
- return mFlags;
- }
-
- /**
- * Returns whether this item is browsable.
- * @see #FLAG_BROWSABLE
- */
- public boolean isBrowsable() {
- return (mFlags & FLAG_BROWSABLE) != 0;
- }
-
- /**
- * Returns whether this item is playable.
- * @see #FLAG_PLAYABLE
- */
- public boolean isPlayable() {
- return (mFlags & FLAG_PLAYABLE) != 0;
- }
-
- /**
- * Returns the description of the media.
- */
- public @NonNull MediaDescription getDescription() {
- return mDescription;
- }
-
- /**
- * Returns the media id in the {@link MediaDescription} for this item.
- * @see android.media.MediaMetadata#METADATA_KEY_MEDIA_ID
- */
- public @Nullable String getMediaId() {
- return mDescription.getMediaId();
- }
- }
-
- /**
- * Callbacks for connection related events.
- */
- public static class ConnectionCallback {
- /**
- * Invoked after {@link MediaBrowser#connect()} when the request has successfully completed.
- */
- public void onConnected() {
- }
-
- /**
- * Invoked when the client is disconnected from the media browser.
- */
- public void onConnectionSuspended() {
- }
-
- /**
- * Invoked when the connection to the media browser failed.
- */
- public void onConnectionFailed() {
- }
- }
-
- /**
- * Callbacks for subscription related events.
- */
- public static abstract class SubscriptionCallback {
- Binder mToken;
-
- public SubscriptionCallback() {
- mToken = new Binder();
- }
-
- /**
- * Called when the list of children is loaded or updated.
- *
- * @param parentId The media id of the parent media item.
- * @param children The children which were loaded.
- */
- public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
- }
-
- /**
- * Called when the list of children is loaded or updated.
- *
- * @param parentId The media id of the parent media item.
- * @param children The children which were loaded.
- * @param options The bundle of service-specific arguments sent to the media
- * browser service. The contents of this bundle may affect the
- * information returned when browsing.
- */
- public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
- @NonNull Bundle options) {
- }
-
- /**
- * Called when the id doesn't exist or other errors in subscribing.
- * <p>
- * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
- * called, because some errors may heal themselves.
- * </p>
- *
- * @param parentId The media id of the parent media item whose children could
- * not be loaded.
- */
- public void onError(@NonNull String parentId) {
- }
-
- /**
- * Called when the id doesn't exist or other errors in subscribing.
- * <p>
- * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
- * called, because some errors may heal themselves.
- * </p>
- *
- * @param parentId The media id of the parent media item whose children could
- * not be loaded.
- * @param options The bundle of service-specific arguments sent to the media
- * browser service.
- */
- public void onError(@NonNull String parentId, @NonNull Bundle options) {
- }
- }
-
- /**
- * Callback for receiving the result of {@link #getItem}.
- */
- public static abstract class ItemCallback {
- /**
- * Called when the item has been returned by the connected service.
- *
- * @param item The item that was returned or null if it doesn't exist.
- */
- public void onItemLoaded(MediaItem item) {
- }
-
- /**
- * Called there was an error retrieving it or the connected service doesn't support
- * {@link #getItem}.
- *
- * @param mediaId The media id of the media item which could not be loaded.
- */
- public void onError(@NonNull String mediaId) {
- }
- }
-
- /**
- * ServiceConnection to the other app.
- */
- private class MediaServiceConnection implements ServiceConnection {
- @Override
- public void onServiceConnected(final ComponentName name, final IBinder binder) {
- postOrRun(new Runnable() {
- @Override
- public void run() {
- if (DBG) {
- Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
- + " binder=" + binder);
- dump();
- }
-
- // Make sure we are still the current connection, and that they haven't called
- // disconnect().
- if (!isCurrent("onServiceConnected")) {
- return;
- }
-
- // Save their binder
- mServiceBinder = IMediaBrowserService.Stub.asInterface(binder);
-
- // We make a new mServiceCallbacks each time we connect so that we can drop
- // responses from previous connections.
- mServiceCallbacks = getNewServiceCallbacks();
- mState = CONNECT_STATE_CONNECTING;
-
- // Call connect, which is async. When we get a response from that we will
- // say that we're connected.
- try {
- if (DBG) {
- Log.d(TAG, "ServiceCallbacks.onConnect...");
- dump();
- }
- mServiceBinder.connect(mContext.getPackageName(), mRootHints,
- mServiceCallbacks);
- } catch (RemoteException ex) {
- // Connect failed, which isn't good. But the auto-reconnect on the service
- // will take over and we will come back. We will also get the
- // onServiceDisconnected, which has all the cleanup code. So let that do
- // it.
- Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
- if (DBG) {
- Log.d(TAG, "ServiceCallbacks.onConnect...");
- dump();
- }
- }
- }
- });
- }
-
- @Override
- public void onServiceDisconnected(final ComponentName name) {
- postOrRun(new Runnable() {
- @Override
- public void run() {
- if (DBG) {
- Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
- + " this=" + this + " mServiceConnection=" + mServiceConnection);
- dump();
- }
-
- // Make sure we are still the current connection, and that they haven't called
- // disconnect().
- if (!isCurrent("onServiceDisconnected")) {
- return;
- }
-
- // Clear out what we set in onServiceConnected
- mServiceBinder = null;
- mServiceCallbacks = null;
-
- // And tell the app that it's suspended.
- mState = CONNECT_STATE_SUSPENDED;
- mCallback.onConnectionSuspended();
- }
- });
- }
-
- private void postOrRun(Runnable r) {
- if (Thread.currentThread() == mHandler.getLooper().getThread()) {
- r.run();
- } else {
- mHandler.post(r);
- }
- }
-
- /**
- * Return true if this is the current ServiceConnection. Also logs if it's not.
- */
- private boolean isCurrent(String funcName) {
- if (mServiceConnection != this || mState == CONNECT_STATE_DISCONNECTING
- || mState == CONNECT_STATE_DISCONNECTED) {
- if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
- // Check mState, because otherwise this log is noisy.
- Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
- + mServiceConnection + " this=" + this);
- }
- return false;
- }
- return true;
- }
- }
-
- /**
- * Callbacks from the service.
- */
- private static class ServiceCallbacks extends IMediaBrowserServiceCallbacks.Stub {
- private WeakReference<MediaBrowser> mMediaBrowser;
-
- public ServiceCallbacks(MediaBrowser mediaBrowser) {
- mMediaBrowser = new WeakReference<MediaBrowser>(mediaBrowser);
- }
-
- /**
- * The other side has acknowledged our connection. The parameters to this function
- * are the initial data as requested.
- */
- @Override
- public void onConnect(String root, MediaSession.Token session,
- final Bundle extras) {
- MediaBrowser mediaBrowser = mMediaBrowser.get();
- if (mediaBrowser != null) {
- mediaBrowser.onServiceConnected(this, root, session, extras);
- }
- }
-
- /**
- * The other side does not like us. Tell the app via onConnectionFailed.
- */
- @Override
- public void onConnectFailed() {
- MediaBrowser mediaBrowser = mMediaBrowser.get();
- if (mediaBrowser != null) {
- mediaBrowser.onConnectionFailed(this);
- }
- }
-
- @Override
- public void onLoadChildren(String parentId, MediaParceledListSlice list) {
- onLoadChildrenWithOptions(parentId, list, null);
- }
-
- @Override
- public void onLoadChildrenWithOptions(String parentId, MediaParceledListSlice list,
- final Bundle options) {
- MediaBrowser mediaBrowser = mMediaBrowser.get();
- if (mediaBrowser != null) {
- mediaBrowser.onLoadChildren(this, parentId, list, options);
- }
- }
- }
-
- private static class Subscription {
- private final List<SubscriptionCallback> mCallbacks;
- private final List<Bundle> mOptionsList;
-
- public Subscription() {
- mCallbacks = new ArrayList<>();
- mOptionsList = new ArrayList<>();
- }
-
- public boolean isEmpty() {
- return mCallbacks.isEmpty();
- }
-
- public List<Bundle> getOptionsList() {
- return mOptionsList;
- }
-
- public List<SubscriptionCallback> getCallbacks() {
- return mCallbacks;
- }
-
- public SubscriptionCallback getCallback(Context context, Bundle options) {
- if (options != null) {
- options.setClassLoader(context.getClassLoader());
- }
- for (int i = 0; i < mOptionsList.size(); ++i) {
- if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
- return mCallbacks.get(i);
- }
- }
- return null;
- }
-
- public void putCallback(Context context, Bundle options, SubscriptionCallback callback) {
- if (options != null) {
- options.setClassLoader(context.getClassLoader());
- }
- for (int i = 0; i < mOptionsList.size(); ++i) {
- if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
- mCallbacks.set(i, callback);
- return;
- }
- }
- mCallbacks.add(callback);
- mOptionsList.add(options);
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowserUtils.java b/packages/MediaComponents/apex/java/android/media/browse/MediaBrowserUtils.java
deleted file mode 100644
index 2943e60..0000000
--- a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowserUtils.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-package android.media.browse;
-
-import android.os.Bundle;
-
-/**
- * @hide
- */
-public class MediaBrowserUtils {
- public static boolean areSameOptions(Bundle options1, Bundle options2) {
- if (options1 == options2) {
- return true;
- } else if (options1 == null) {
- return options2.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
- && options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
- } else if (options2 == null) {
- return options1.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
- && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
- } else {
- return options1.getInt(MediaBrowser.EXTRA_PAGE, -1)
- == options2.getInt(MediaBrowser.EXTRA_PAGE, -1)
- && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1)
- == options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
- }
- }
-
- public static boolean hasDuplicatedItems(Bundle options1, Bundle options2) {
- int page1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE, -1);
- int page2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE, -1);
- int pageSize1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
- int pageSize2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-
- int startIndex1, startIndex2, endIndex1, endIndex2;
- if (page1 == -1 || pageSize1 == -1) {
- startIndex1 = 0;
- endIndex1 = Integer.MAX_VALUE;
- } else {
- startIndex1 = pageSize1 * page1;
- endIndex1 = startIndex1 + pageSize1 - 1;
- }
-
- if (page2 == -1 || pageSize2 == -1) {
- startIndex2 = 0;
- endIndex2 = Integer.MAX_VALUE;
- } else {
- startIndex2 = pageSize2 * page2;
- endIndex2 = startIndex2 + pageSize2 - 1;
- }
-
- if (startIndex1 <= startIndex2 && startIndex2 <= endIndex1) {
- return true;
- } else if (startIndex1 <= endIndex2 && endIndex2 <= endIndex1) {
- return true;
- }
- return false;
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/IActiveSessionsListener.aidl b/packages/MediaComponents/apex/java/android/media/session/IActiveSessionsListener.aidl
deleted file mode 100644
index 4b9e4bd..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/IActiveSessionsListener.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/* Copyright (C) 2014 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.
- */
-
-package android.media.session;
-
-import android.media.session.MediaSession;
-
-/**
- * Listens for changes to the list of active sessions.
- * @hide
- */
-oneway interface IActiveSessionsListener {
- void onActiveSessionsChanged(in List<MediaSession.Token> sessions);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ICallback.aidl b/packages/MediaComponents/apex/java/android/media/session/ICallback.aidl
deleted file mode 100644
index 322bffa..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ICallback.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2016 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.
- */
-
-package android.media.session;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.media.session.MediaSession;
-import android.view.KeyEvent;
-
-/**
- * @hide
- */
-oneway interface ICallback {
- void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event,
- in MediaSession.Token sessionToken);
- void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event,
- in ComponentName mediaButtonReceiver);
-
- void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken);
- void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver);
-}
-
diff --git a/packages/MediaComponents/apex/java/android/media/session/IOnMediaKeyListener.aidl b/packages/MediaComponents/apex/java/android/media/session/IOnMediaKeyListener.aidl
deleted file mode 100644
index aa98ea3..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/IOnMediaKeyListener.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Copyright (C) 2016 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.
- */
-
-package android.media.session;
-
-import android.os.ResultReceiver;
-import android.view.KeyEvent;
-
-/**
- * Listener to handle media key.
- * @hide
- */
-oneway interface IOnMediaKeyListener {
- void onMediaKey(in KeyEvent event, in ResultReceiver result);
-}
-
diff --git a/packages/MediaComponents/apex/java/android/media/session/IOnVolumeKeyLongPressListener.aidl b/packages/MediaComponents/apex/java/android/media/session/IOnVolumeKeyLongPressListener.aidl
deleted file mode 100644
index 07b8347..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/IOnVolumeKeyLongPressListener.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Copyright (C) 2016 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.
- */
-
-package android.media.session;
-
-import android.view.KeyEvent;
-
-/**
- * Listener to handle volume key long-press.
- * @hide
- */
-oneway interface IOnVolumeKeyLongPressListener {
- void onVolumeKeyLongPress(in KeyEvent event);
-}
-
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISession.aidl b/packages/MediaComponents/apex/java/android/media/session/ISession.aidl
deleted file mode 100644
index 14b1c64..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISession.aidl
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright (C) 2014 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.
- */
-
-package android.media.session;
-
-import android.app.PendingIntent;
-//import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.ISessionController;
-import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * Interface to a MediaSession in the system.
- * @hide
- */
-interface ISession {
- void sendEvent(String event, in Bundle data);
- ISessionController getController();
- void setFlags(int flags);
- void setActive(boolean active);
- void setMediaButtonReceiver(in PendingIntent mbr);
- void setLaunchPendingIntent(in PendingIntent pi);
- void destroy();
-
- // These commands are for the TransportPerformer
- void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
- void setPlaybackState(in PlaybackState state);
- void setQueue(in MediaParceledListSlice queue);
- void setQueueTitle(CharSequence title);
- void setExtras(in Bundle extras);
- void setRatingType(int type);
-
- // These commands relate to volume handling
- //TODO(b/119751592): Decide if AudioAttributes should be updated.
- //void setPlaybackToLocal(in AudioAttributes attributes);
- void setPlaybackToRemote(int control, int max);
- void setCurrentVolume(int currentVolume);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionCallback.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionCallback.aidl
deleted file mode 100644
index 626338d..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionCallback.aidl
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Copyright (C) 2014 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.
- */
-
-package android.media.session;
-
-import android.content.Intent;
-import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * @hide
- */
-oneway interface ISessionCallback {
- void onCommand(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String command, in Bundle args, in ResultReceiver cb);
- void onMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
- int sequenceNumber, in ResultReceiver cb);
- void onMediaButtonFromController(String packageName, int pid, int uid,
- ISessionControllerCallback caller, in Intent mediaButtonIntent);
-
- // These callbacks are for the TransportPerformer
- void onPrepare(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onPrepareFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId, in Bundle extras);
- void onPrepareFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query, in Bundle extras);
- void onPrepareFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
- in Uri uri, in Bundle extras);
- void onPlay(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onPlayFromMediaId(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String mediaId, in Bundle extras);
- void onPlayFromSearch(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String query, in Bundle extras);
- void onPlayFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
- in Uri uri, in Bundle extras);
- void onSkipToTrack(String packageName, int pid, int uid, ISessionControllerCallback caller,
- long id);
- void onPause(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onStop(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onNext(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onPrevious(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onFastForward(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onRewind(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onSeekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
- long pos);
- void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
- in Rating rating);
- void onCustomAction(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String action, in Bundle args);
-
- // These callbacks are for volume handling
- void onAdjustVolume(String packageName, int pid, int uid, ISessionControllerCallback caller,
- int direction);
- void onSetVolumeTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int value);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl
deleted file mode 100644
index 433b12f..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl
+++ /dev/null
@@ -1,88 +0,0 @@
-/* Copyright (C) 2014 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.
- */
-
-package android.media.session;
-
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
-import android.media.session.MediaSession;
-import android.media.session.ParcelableVolumeInfo;
-import android.media.session.PlaybackState;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.view.KeyEvent;
-
-import java.util.List;
-
-/**
- * Interface to MediaSessionRecord in the system.
- * @hide
- */
-interface ISessionController {
- void sendCommand(String packageName, ISessionControllerCallback caller,
- String command, in Bundle args, in ResultReceiver cb);
- boolean sendMediaButton(String packageName, ISessionControllerCallback caller,
- boolean asSystemService, in KeyEvent mediaButton);
- void registerCallbackListener(String packageName, ISessionControllerCallback cb);
- void unregisterCallbackListener(ISessionControllerCallback cb);
- boolean isTransportControlEnabled();
- String getPackageName();
- String getTag();
- PendingIntent getLaunchPendingIntent();
- long getFlags();
- ParcelableVolumeInfo getVolumeAttributes();
- void adjustVolume(String packageName, String opPackageName, ISessionControllerCallback caller,
- boolean asSystemService, int direction, int flags);
- void setVolumeTo(String packageName, String opPackageName, ISessionControllerCallback caller,
- int value, int flags);
-
- // These commands are for the TransportControls
- void prepare(String packageName, ISessionControllerCallback caller);
- void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
- String mediaId, in Bundle extras);
- void prepareFromSearch(String packageName, ISessionControllerCallback caller,
- String string, in Bundle extras);
- void prepareFromUri(String packageName, ISessionControllerCallback caller,
- in Uri uri, in Bundle extras);
- void play(String packageName, ISessionControllerCallback caller);
- void playFromMediaId(String packageName, ISessionControllerCallback caller,
- String mediaId, in Bundle extras);
- void playFromSearch(String packageName, ISessionControllerCallback caller,
- String string, in Bundle extras);
- void playFromUri(String packageName, ISessionControllerCallback caller,
- in Uri uri, in Bundle extras);
- void skipToQueueItem(String packageName, ISessionControllerCallback caller, long id);
- void pause(String packageName, ISessionControllerCallback caller);
- void stop(String packageName, ISessionControllerCallback caller);
- void next(String packageName, ISessionControllerCallback caller);
- void previous(String packageName, ISessionControllerCallback caller);
- void fastForward(String packageName, ISessionControllerCallback caller);
- void rewind(String packageName, ISessionControllerCallback caller);
- void seekTo(String packageName, ISessionControllerCallback caller, long pos);
- void rate(String packageName, ISessionControllerCallback caller, in Rating rating);
- void sendCustomAction(String packageName, ISessionControllerCallback caller,
- String action, in Bundle args);
- MediaMetadata getMetadata();
- PlaybackState getPlaybackState();
- MediaParceledListSlice getQueue();
- CharSequence getQueueTitle();
- Bundle getExtras();
- int getRatingType();
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionControllerCallback.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionControllerCallback.aidl
deleted file mode 100644
index f5cc4f6..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionControllerCallback.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Copyright (C) 2014 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.
- */
-
-package android.media.session;
-
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.ParcelableVolumeInfo;
-import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-
-/**
- * @hide
- */
-oneway interface ISessionControllerCallback {
- void onEvent(String event, in Bundle extras);
- void onSessionDestroyed();
-
- // These callbacks are for the TransportController
- void onPlaybackStateChanged(in PlaybackState state);
- void onMetadataChanged(in MediaMetadata metadata);
- void onQueueChanged(in MediaParceledListSlice queue);
- void onQueueTitleChanged(CharSequence title);
- void onExtrasChanged(in Bundle extras);
- void onVolumeInfoChanged(in ParcelableVolumeInfo info);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl
deleted file mode 100644
index d6c226f..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (C) 2014 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.
- */
-
-package android.media.session;
-
-import android.content.ComponentName;
-import android.media.IRemoteVolumeController;
-import android.media.session.IActiveSessionsListener;
-import android.media.session.ICallback;
-import android.media.session.IOnMediaKeyListener;
-import android.media.session.IOnVolumeKeyLongPressListener;
-import android.media.session.ISession;
-import android.media.session.ISessionCallback;
-import android.os.Bundle;
-import android.view.KeyEvent;
-
-/**
- * Interface to the MediaSessionManagerService
- * @hide
- */
-interface ISessionManager {
- ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
- List<IBinder> getSessions(in ComponentName compName, int userId);
- void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
- boolean needWakeLock);
- void dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService,
- in KeyEvent keyEvent, int stream, boolean musicOnly);
- void dispatchAdjustVolume(String packageName, String opPackageName, int suggestedStream,
- int delta, int flags);
- void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
- int userId);
- void removeSessionsListener(in IActiveSessionsListener listener);
-
- // This is for the system volume UI only
- void setRemoteVolumeController(in IRemoteVolumeController rvc);
-
- // For PhoneWindowManager to precheck media keys
- boolean isGlobalPriorityActive();
-
- void setCallback(in ICallback callback);
- void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
- void setOnMediaKeyListener(in IOnMediaKeyListener listener);
-
- // MediaSession2
- boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaController.java b/packages/MediaComponents/apex/java/android/media/session/MediaController.java
deleted file mode 100644
index 65682a8..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/MediaController.java
+++ /dev/null
@@ -1,1190 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.media.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.VolumeProvider;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.KeyEvent;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Allows an app to interact with an ongoing media session. Media buttons and
- * other commands can be sent to the session. A callback may be registered to
- * receive updates from the session, such as metadata and play state changes.
- * <p>
- * A MediaController can be created through {@link MediaSessionManager} if you
- * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or are an
- * enabled notification listener or by getting a {@link MediaSession.Token}
- * directly from the session owner.
- * <p>
- * MediaController objects are thread-safe.
- */
-public final class MediaController {
- private static final String TAG = "MediaController";
-
- private static final int MSG_EVENT = 1;
- private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
- private static final int MSG_UPDATE_METADATA = 3;
- private static final int MSG_UPDATE_VOLUME = 4;
- private static final int MSG_UPDATE_QUEUE = 5;
- private static final int MSG_UPDATE_QUEUE_TITLE = 6;
- private static final int MSG_UPDATE_EXTRAS = 7;
- private static final int MSG_DESTROYED = 8;
-
- private final ISessionController mSessionBinder;
-
- private final MediaSession.Token mToken;
- private final Context mContext;
- private final CallbackStub mCbStub = new CallbackStub(this);
- private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
- private final Object mLock = new Object();
-
- private boolean mCbRegistered = false;
- private String mPackageName;
- private String mTag;
-
- private final TransportControls mTransportControls;
-
- /**
- * Call for creating a MediaController directly from a binder. Should only
- * be used by framework code.
- *
- * @hide
- */
- public MediaController(Context context, ISessionController sessionBinder) {
- if (sessionBinder == null) {
- throw new IllegalArgumentException("Session token cannot be null");
- }
- if (context == null) {
- throw new IllegalArgumentException("Context cannot be null");
- }
- mSessionBinder = sessionBinder;
- mTransportControls = new TransportControls();
- mToken = new MediaSession.Token(sessionBinder);
- mContext = context;
- }
-
- /**
- * Create a new MediaController from a session's token.
- *
- * @param context The caller's context.
- * @param token The token for the session.
- */
- public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) {
- this(context, token.getBinder());
- }
-
- /**
- * Get a {@link TransportControls} instance to send transport actions to
- * the associated session.
- *
- * @return A transport controls instance.
- */
- public @NonNull TransportControls getTransportControls() {
- return mTransportControls;
- }
-
- /**
- * Send the specified media button event to the session. Only media keys can
- * be sent by this method, other keys will be ignored.
- *
- * @param keyEvent The media button event to dispatch.
- * @return true if the event was sent to the session, false otherwise.
- */
- public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
- return dispatchMediaButtonEventInternal(false, keyEvent);
- }
-
- /**
- * Dispatches the media button event as system service to the session.
- * <p>
- * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
- * foreground activity didn't consume the key from the hardware devices.
- *
- * @param keyEvent media key event
- * @return {@code true} if the event was sent to the session, {@code false} otherwise
- * @hide
- */
- public boolean dispatchMediaButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
- return dispatchMediaButtonEventInternal(true, keyEvent);
- }
-
- private boolean dispatchMediaButtonEventInternal(boolean asSystemService,
- @NonNull KeyEvent keyEvent) {
- if (keyEvent == null) {
- throw new IllegalArgumentException("KeyEvent may not be null");
- }
- if (!KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
- return false;
- }
- try {
- return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub,
- asSystemService, keyEvent);
- } catch (RemoteException e) {
- // System is dead. =(
- }
- return false;
- }
-
- /**
- * Dispatches the volume button event as system service to the session.
- * <p>
- * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
- * foreground activity didn't consume the key from the hardware devices.
- *
- * @param keyEvent volume key event
- * @hide
- */
- public void dispatchVolumeButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
- switch (keyEvent.getAction()) {
- case KeyEvent.ACTION_DOWN: {
- int direction = 0;
- switch (keyEvent.getKeyCode()) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- direction = AudioManager.ADJUST_RAISE;
- break;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- direction = AudioManager.ADJUST_LOWER;
- break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- direction = AudioManager.ADJUST_TOGGLE_MUTE;
- break;
- }
- try {
- mSessionBinder.adjustVolume(mContext.getPackageName(),
- mContext.getOpPackageName(), mCbStub, true, direction,
- AudioManager.FLAG_SHOW_UI);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling adjustVolumeBy", e);
- }
- }
-
- case KeyEvent.ACTION_UP: {
- final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
- | AudioManager.FLAG_FROM_KEY;
- try {
- mSessionBinder.adjustVolume(mContext.getPackageName(),
- mContext.getOpPackageName(), mCbStub, true, 0, flags);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling adjustVolumeBy", e);
- }
- }
- }
- }
-
- /**
- * Get the current playback state for this session.
- *
- * @return The current PlaybackState or null
- */
- public @Nullable PlaybackState getPlaybackState() {
- try {
- return mSessionBinder.getPlaybackState();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getPlaybackState.", e);
- return null;
- }
- }
-
- /**
- * Get the current metadata for this session.
- *
- * @return The current MediaMetadata or null.
- */
- public @Nullable MediaMetadata getMetadata() {
- try {
- return mSessionBinder.getMetadata();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getMetadata.", e);
- return null;
- }
- }
-
- /**
- * Get the current play queue for this session if one is set. If you only
- * care about the current item {@link #getMetadata()} should be used.
- *
- * @return The current play queue or null.
- */
- public @Nullable List<MediaSession.QueueItem> getQueue() {
- try {
- MediaParceledListSlice queue = mSessionBinder.getQueue();
- if (queue != null) {
- return queue.getList();
- }
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getQueue.", e);
- }
- return null;
- }
-
- /**
- * Get the queue title for this session.
- */
- public @Nullable CharSequence getQueueTitle() {
- try {
- return mSessionBinder.getQueueTitle();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getQueueTitle", e);
- }
- return null;
- }
-
- /**
- * Get the extras for this session.
- */
- public @Nullable Bundle getExtras() {
- try {
- return mSessionBinder.getExtras();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getExtras", e);
- }
- return null;
- }
-
- /**
- * Get the rating type supported by the session. One of:
- * <ul>
- * <li>{@link Rating#RATING_NONE}</li>
- * <li>{@link Rating#RATING_HEART}</li>
- * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
- * <li>{@link Rating#RATING_3_STARS}</li>
- * <li>{@link Rating#RATING_4_STARS}</li>
- * <li>{@link Rating#RATING_5_STARS}</li>
- * <li>{@link Rating#RATING_PERCENTAGE}</li>
- * </ul>
- *
- * @return The supported rating type
- */
- public int getRatingType() {
- try {
- return mSessionBinder.getRatingType();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getRatingType.", e);
- return Rating.RATING_NONE;
- }
- }
-
- /**
- * Get the flags for this session. Flags are defined in {@link MediaSession}.
- *
- * @return The current set of flags for the session.
- */
- public @MediaSession.SessionFlags long getFlags() {
- try {
- return mSessionBinder.getFlags();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getFlags.", e);
- }
- return 0;
- }
-
- /**
- * Get the current playback info for this session.
- *
- * @return The current playback info or null.
- */
- public @Nullable PlaybackInfo getPlaybackInfo() {
- try {
- ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes();
- return new PlaybackInfo(result.volumeType, result.audioAttrs, result.controlType,
- result.maxVolume, result.currentVolume);
-
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getAudioInfo.", e);
- }
- return null;
- }
-
- /**
- * Get an intent for launching UI associated with this session if one
- * exists.
- *
- * @return A {@link PendingIntent} to launch UI or null.
- */
- public @Nullable PendingIntent getSessionActivity() {
- try {
- return mSessionBinder.getLaunchPendingIntent();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getPendingIntent.", e);
- }
- return null;
- }
-
- /**
- * Get the token for the session this is connected to.
- *
- * @return The token for the connected session.
- */
- public @NonNull MediaSession.Token getSessionToken() {
- return mToken;
- }
-
- /**
- * Set the volume of the output this session is playing on. The command will
- * be ignored if it does not support
- * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
- * {@link AudioManager} may be used to affect the handling.
- *
- * @see #getPlaybackInfo()
- * @param value The value to set it to, between 0 and the reported max.
- * @param flags Flags from {@link AudioManager} to include with the volume
- * request.
- */
- public void setVolumeTo(int value, int flags) {
- try {
- mSessionBinder.setVolumeTo(mContext.getPackageName(), mContext.getOpPackageName(),
- mCbStub, value, flags);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling setVolumeTo.", e);
- }
- }
-
- /**
- * Adjust the volume of the output this session is playing on. The direction
- * must be one of {@link AudioManager#ADJUST_LOWER},
- * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
- * The command will be ignored if the session does not support
- * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or
- * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
- * {@link AudioManager} may be used to affect the handling.
- *
- * @see #getPlaybackInfo()
- * @param direction The direction to adjust the volume in.
- * @param flags Any flags to pass with the command.
- */
- public void adjustVolume(int direction, int flags) {
- try {
- mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(),
- mCbStub, false, direction, flags);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
- }
- }
-
- /**
- * Registers a callback to receive updates from the Session. Updates will be
- * posted on the caller's thread.
- *
- * @param callback The callback object, must not be null.
- */
- public void registerCallback(@NonNull Callback callback) {
- registerCallback(callback, null);
- }
-
- /**
- * Registers a callback to receive updates from the session. Updates will be
- * posted on the specified handler's thread.
- *
- * @param callback The callback object, must not be null.
- * @param handler The handler to post updates on. If null the callers thread
- * will be used.
- */
- public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
- if (callback == null) {
- throw new IllegalArgumentException("callback must not be null");
- }
- if (handler == null) {
- handler = new Handler();
- }
- synchronized (mLock) {
- addCallbackLocked(callback, handler);
- }
- }
-
- /**
- * Unregisters the specified callback. If an update has already been posted
- * you may still receive it after calling this method.
- *
- * @param callback The callback to remove.
- */
- public void unregisterCallback(@NonNull Callback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("callback must not be null");
- }
- synchronized (mLock) {
- removeCallbackLocked(callback);
- }
- }
-
- /**
- * Sends a generic command to the session. It is up to the session creator
- * to decide what commands and parameters they will support. As such,
- * commands should only be sent to sessions that the controller owns.
- *
- * @param command The command to send
- * @param args Any parameters to include with the command
- * @param cb The callback to receive the result on
- */
- public void sendCommand(@NonNull String command, @Nullable Bundle args,
- @Nullable ResultReceiver cb) {
- if (TextUtils.isEmpty(command)) {
- throw new IllegalArgumentException("command cannot be null or empty");
- }
- try {
- mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb);
- } catch (RemoteException e) {
- Log.d(TAG, "Dead object in sendCommand.", e);
- }
- }
-
- /**
- * Get the session owner's package name.
- *
- * @return The package name of of the session owner.
- */
- public String getPackageName() {
- if (mPackageName == null) {
- try {
- mPackageName = mSessionBinder.getPackageName();
- } catch (RemoteException e) {
- Log.d(TAG, "Dead object in getPackageName.", e);
- }
- }
- return mPackageName;
- }
-
- /**
- * Get the session's tag for debugging purposes.
- *
- * @return The session's tag.
- * @hide
- */
- public String getTag() {
- if (mTag == null) {
- try {
- mTag = mSessionBinder.getTag();
- } catch (RemoteException e) {
- Log.d(TAG, "Dead object in getTag.", e);
- }
- }
- return mTag;
- }
-
- /*
- * @hide
- */
- ISessionController getSessionBinder() {
- return mSessionBinder;
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage
- public boolean controlsSameSession(MediaController other) {
- if (other == null) return false;
- return mSessionBinder.asBinder() == other.getSessionBinder().asBinder();
- }
-
- private void addCallbackLocked(Callback cb, Handler handler) {
- if (getHandlerForCallbackLocked(cb) != null) {
- Log.w(TAG, "Callback is already added, ignoring");
- return;
- }
- MessageHandler holder = new MessageHandler(handler.getLooper(), cb);
- mCallbacks.add(holder);
- holder.mRegistered = true;
-
- if (!mCbRegistered) {
- try {
- mSessionBinder.registerCallbackListener(mContext.getPackageName(), mCbStub);
- mCbRegistered = true;
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in registerCallback", e);
- }
- }
- }
-
- private boolean removeCallbackLocked(Callback cb) {
- boolean success = false;
- for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- MessageHandler handler = mCallbacks.get(i);
- if (cb == handler.mCallback) {
- mCallbacks.remove(i);
- success = true;
- handler.mRegistered = false;
- }
- }
- if (mCbRegistered && mCallbacks.size() == 0) {
- try {
- mSessionBinder.unregisterCallbackListener(mCbStub);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in removeCallbackLocked");
- }
- mCbRegistered = false;
- }
- return success;
- }
-
- private MessageHandler getHandlerForCallbackLocked(Callback cb) {
- if (cb == null) {
- throw new IllegalArgumentException("Callback cannot be null");
- }
- for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- MessageHandler handler = mCallbacks.get(i);
- if (cb == handler.mCallback) {
- return handler;
- }
- }
- return null;
- }
-
- private final void postMessage(int what, Object obj, Bundle data) {
- synchronized (mLock) {
- for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- mCallbacks.get(i).post(what, obj, data);
- }
- }
- }
-
- /**
- * Callback for receiving updates from the session. A Callback can be
- * registered using {@link #registerCallback}.
- */
- public static abstract class Callback {
- /**
- * Override to handle the session being destroyed. The session is no
- * longer valid after this call and calls to it will be ignored.
- */
- public void onSessionDestroyed() {
- }
-
- /**
- * Override to handle custom events sent by the session owner without a
- * specified interface. Controllers should only handle these for
- * sessions they own.
- *
- * @param event The event from the session.
- * @param extras Optional parameters for the event, may be null.
- */
- public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) {
- }
-
- /**
- * Override to handle changes in playback state.
- *
- * @param state The new playback state of the session
- */
- public void onPlaybackStateChanged(@Nullable PlaybackState state) {
- }
-
- /**
- * Override to handle changes to the current metadata.
- *
- * @param metadata The current metadata for the session or null if none.
- * @see MediaMetadata
- */
- public void onMetadataChanged(@Nullable MediaMetadata metadata) {
- }
-
- /**
- * Override to handle changes to items in the queue.
- *
- * @param queue A list of items in the current play queue. It should
- * include the currently playing item as well as previous and
- * upcoming items if applicable.
- * @see MediaSession.QueueItem
- */
- public void onQueueChanged(@Nullable List<MediaSession.QueueItem> queue) {
- }
-
- /**
- * Override to handle changes to the queue title.
- *
- * @param title The title that should be displayed along with the play queue such as
- * "Now Playing". May be null if there is no such title.
- */
- public void onQueueTitleChanged(@Nullable CharSequence title) {
- }
-
- /**
- * Override to handle changes to the {@link MediaSession} extras.
- *
- * @param extras The extras that can include other information associated with the
- * {@link MediaSession}.
- */
- public void onExtrasChanged(@Nullable Bundle extras) {
- }
-
- /**
- * Override to handle changes to the audio info.
- *
- * @param info The current audio info for this session.
- */
- public void onAudioInfoChanged(PlaybackInfo info) {
- }
- }
-
- /**
- * Interface for controlling media playback on a session. This allows an app
- * to send media transport commands to the session.
- */
- public final class TransportControls {
- private static final String TAG = "TransportController";
-
- private TransportControls() {
- }
-
- /**
- * Request that the player prepare its playback. In other words, other sessions can continue
- * to play during the preparation of this session. This method can be used to speed up the
- * start of the playback. Once the preparation is done, the session will change its playback
- * state to {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to
- * start playback.
- */
- public void prepare() {
- try {
- mSessionBinder.prepare(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare.", e);
- }
- }
-
- /**
- * Request that the player prepare playback for a specific media id. In other words, other
- * sessions can continue to play during the preparation of this session. This method can be
- * used to speed up the start of the playback. Once the preparation is done, the session
- * will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
- * {@link #play} can be called to start playback. If the preparation is not needed,
- * {@link #playFromMediaId} can be directly called without this method.
- *
- * @param mediaId The id of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be prepared.
- */
- public void prepareFromMediaId(String mediaId, Bundle extras) {
- if (TextUtils.isEmpty(mediaId)) {
- throw new IllegalArgumentException(
- "You must specify a non-empty String for prepareFromMediaId.");
- }
- try {
- mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
- extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
- }
- }
-
- /**
- * Request that the player prepare playback for a specific search query. An empty or null
- * query should be treated as a request to prepare any music. In other words, other sessions
- * can continue to play during the preparation of this session. This method can be used to
- * speed up the start of the playback. Once the preparation is done, the session will
- * change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
- * {@link #play} can be called to start playback. If the preparation is not needed,
- * {@link #playFromSearch} can be directly called without this method.
- *
- * @param query The search query.
- * @param extras Optional extras that can include extra information
- * about the query.
- */
- public void prepareFromSearch(String query, Bundle extras) {
- if (query == null) {
- // This is to remain compatible with
- // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
- query = "";
- }
- try {
- mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query,
- extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
- }
- }
-
- /**
- * Request that the player prepare playback for a specific {@link Uri}. In other words,
- * other sessions can continue to play during the preparation of this session. This method
- * can be used to speed up the start of the playback. Once the preparation is done, the
- * session will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
- * {@link #play} can be called to start playback. If the preparation is not needed,
- * {@link #playFromUri} can be directly called without this method.
- *
- * @param uri The URI of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be prepared.
- */
- public void prepareFromUri(Uri uri, Bundle extras) {
- if (uri == null || Uri.EMPTY.equals(uri)) {
- throw new IllegalArgumentException(
- "You must specify a non-empty Uri for prepareFromUri.");
- }
- try {
- mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
- }
- }
-
- /**
- * Request that the player start its playback at its current position.
- */
- public void play() {
- try {
- mSessionBinder.play(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play.", e);
- }
- }
-
- /**
- * Request that the player start playback for a specific media id.
- *
- * @param mediaId The id of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be played.
- */
- public void playFromMediaId(String mediaId, Bundle extras) {
- if (TextUtils.isEmpty(mediaId)) {
- throw new IllegalArgumentException(
- "You must specify a non-empty String for playFromMediaId.");
- }
- try {
- mSessionBinder.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
- extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
- }
- }
-
- /**
- * Request that the player start playback for a specific search query.
- * An empty or null query should be treated as a request to play any
- * music.
- *
- * @param query The search query.
- * @param extras Optional extras that can include extra information
- * about the query.
- */
- public void playFromSearch(String query, Bundle extras) {
- if (query == null) {
- // This is to remain compatible with
- // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
- query = "";
- }
- try {
- mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play(" + query + ").", e);
- }
- }
-
- /**
- * Request that the player start playback for a specific {@link Uri}.
- *
- * @param uri The URI of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be played.
- */
- public void playFromUri(Uri uri, Bundle extras) {
- if (uri == null || Uri.EMPTY.equals(uri)) {
- throw new IllegalArgumentException(
- "You must specify a non-empty Uri for playFromUri.");
- }
- try {
- mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play(" + uri + ").", e);
- }
- }
-
- /**
- * Play an item with a specific id in the play queue. If you specify an
- * id that is not in the play queue, the behavior is undefined.
- */
- public void skipToQueueItem(long id) {
- try {
- mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
- }
- }
-
- /**
- * Request that the player pause its playback and stay at its current
- * position.
- */
- public void pause() {
- try {
- mSessionBinder.pause(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling pause.", e);
- }
- }
-
- /**
- * Request that the player stop its playback; it may clear its state in
- * whatever way is appropriate.
- */
- public void stop() {
- try {
- mSessionBinder.stop(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling stop.", e);
- }
- }
-
- /**
- * Move to a new location in the media stream.
- *
- * @param pos Position to move to, in milliseconds.
- */
- public void seekTo(long pos) {
- try {
- mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling seekTo.", e);
- }
- }
-
- /**
- * Start fast forwarding. If playback is already fast forwarding this
- * may increase the rate.
- */
- public void fastForward() {
- try {
- mSessionBinder.fastForward(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling fastForward.", e);
- }
- }
-
- /**
- * Skip to the next item.
- */
- public void skipToNext() {
- try {
- mSessionBinder.next(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling next.", e);
- }
- }
-
- /**
- * Start rewinding. If playback is already rewinding this may increase
- * the rate.
- */
- public void rewind() {
- try {
- mSessionBinder.rewind(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling rewind.", e);
- }
- }
-
- /**
- * Skip to the previous item.
- */
- public void skipToPrevious() {
- try {
- mSessionBinder.previous(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling previous.", e);
- }
- }
-
- /**
- * Rate the current content. This will cause the rating to be set for
- * the current user. The Rating type must match the type returned by
- * {@link #getRatingType()}.
- *
- * @param rating The rating to set for the current content
- */
- public void setRating(Rating rating) {
- try {
- mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling rate.", e);
- }
- }
-
- /**
- * Send a custom action back for the {@link MediaSession} to perform.
- *
- * @param customAction The action to perform.
- * @param args Optional arguments to supply to the {@link MediaSession} for this
- * custom action.
- */
- public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
- @Nullable Bundle args) {
- if (customAction == null) {
- throw new IllegalArgumentException("CustomAction cannot be null.");
- }
- sendCustomAction(customAction.getAction(), args);
- }
-
- /**
- * Send the id and args from a custom action back for the {@link MediaSession} to perform.
- *
- * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args)
- * @param action The action identifier of the {@link PlaybackState.CustomAction} as
- * specified by the {@link MediaSession}.
- * @param args Optional arguments to supply to the {@link MediaSession} for this
- * custom action.
- */
- public void sendCustomAction(@NonNull String action, @Nullable Bundle args) {
- if (TextUtils.isEmpty(action)) {
- throw new IllegalArgumentException("CustomAction cannot be null.");
- }
- try {
- mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args);
- } catch (RemoteException e) {
- Log.d(TAG, "Dead object in sendCustomAction.", e);
- }
- }
- }
-
- /**
- * Holds information about the current playback and how audio is handled for
- * this session.
- */
- public static final class PlaybackInfo {
- /**
- * The session uses remote playback.
- */
- public static final int PLAYBACK_TYPE_REMOTE = 2;
- /**
- * The session uses local playback.
- */
- public static final int PLAYBACK_TYPE_LOCAL = 1;
-
- private final int mVolumeType;
- private final int mVolumeControl;
- private final int mMaxVolume;
- private final int mCurrentVolume;
- private final AudioAttributes mAudioAttrs;
-
- /**
- * @hide
- */
- public PlaybackInfo(int type, AudioAttributes attrs, int control, int max, int current) {
- mVolumeType = type;
- mAudioAttrs = attrs;
- mVolumeControl = control;
- mMaxVolume = max;
- mCurrentVolume = current;
- }
-
- /**
- * Get the type of playback which affects volume handling. One of:
- * <ul>
- * <li>{@link #PLAYBACK_TYPE_LOCAL}</li>
- * <li>{@link #PLAYBACK_TYPE_REMOTE}</li>
- * </ul>
- *
- * @return The type of playback this session is using.
- */
- public int getPlaybackType() {
- return mVolumeType;
- }
-
- /**
- * Get the audio attributes for this session. The attributes will affect
- * volume handling for the session. When the volume type is
- * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the
- * remote volume handler.
- *
- * @return The attributes for this session.
- */
- public AudioAttributes getAudioAttributes() {
- return mAudioAttrs;
- }
-
- /**
- * Get the type of volume control that can be used. One of:
- * <ul>
- * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li>
- * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li>
- * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li>
- * </ul>
- *
- * @return The type of volume control that may be used with this
- * session.
- */
- public int getVolumeControl() {
- return mVolumeControl;
- }
-
- /**
- * Get the maximum volume that may be set for this session.
- *
- * @return The maximum allowed volume where this session is playing.
- */
- public int getMaxVolume() {
- return mMaxVolume;
- }
-
- /**
- * Get the current volume for this session.
- *
- * @return The current volume where this session is playing.
- */
- public int getCurrentVolume() {
- return mCurrentVolume;
- }
- }
-
- private final static class CallbackStub extends ISessionControllerCallback.Stub {
- private final WeakReference<MediaController> mController;
-
- public CallbackStub(MediaController controller) {
- mController = new WeakReference<MediaController>(controller);
- }
-
- @Override
- public void onSessionDestroyed() {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_DESTROYED, null, null);
- }
- }
-
- @Override
- public void onEvent(String event, Bundle extras) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_EVENT, event, extras);
- }
- }
-
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null);
- }
- }
-
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_METADATA, metadata, null);
- }
- }
-
- @Override
- public void onQueueChanged(MediaParceledListSlice parceledQueue) {
- List<MediaSession.QueueItem> queue = parceledQueue == null ? null : parceledQueue
- .getList();
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
- }
- }
-
- @Override
- public void onQueueTitleChanged(CharSequence title) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null);
- }
- }
-
- @Override
- public void onExtrasChanged(Bundle extras) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_EXTRAS, extras, null);
- }
- }
-
- @Override
- public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) {
- MediaController controller = mController.get();
- if (controller != null) {
- PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs,
- pvi.controlType, pvi.maxVolume, pvi.currentVolume);
- controller.postMessage(MSG_UPDATE_VOLUME, info, null);
- }
- }
-
- }
-
- private final static class MessageHandler extends Handler {
- private final MediaController.Callback mCallback;
- private boolean mRegistered = false;
-
- public MessageHandler(Looper looper, MediaController.Callback cb) {
- super(looper);
- mCallback = cb;
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (!mRegistered) {
- return;
- }
- switch (msg.what) {
- case MSG_EVENT:
- mCallback.onSessionEvent((String) msg.obj, msg.getData());
- break;
- case MSG_UPDATE_PLAYBACK_STATE:
- mCallback.onPlaybackStateChanged((PlaybackState) msg.obj);
- break;
- case MSG_UPDATE_METADATA:
- mCallback.onMetadataChanged((MediaMetadata) msg.obj);
- break;
- case MSG_UPDATE_QUEUE:
- mCallback.onQueueChanged((List<MediaSession.QueueItem>) msg.obj);
- break;
- case MSG_UPDATE_QUEUE_TITLE:
- mCallback.onQueueTitleChanged((CharSequence) msg.obj);
- break;
- case MSG_UPDATE_EXTRAS:
- mCallback.onExtrasChanged((Bundle) msg.obj);
- break;
- case MSG_UPDATE_VOLUME:
- mCallback.onAudioInfoChanged((PlaybackInfo) msg.obj);
- break;
- case MSG_DESTROYED:
- mCallback.onSessionDestroyed();
- break;
- }
- }
-
- public void post(int what, Object obj, Bundle data) {
- Message msg = obtainMessage(what, obj);
- msg.setAsynchronous(true);
- msg.setData(data);
- msg.sendToTarget();
- }
- }
-
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaSession.aidl b/packages/MediaComponents/apex/java/android/media/session/MediaSession.aidl
deleted file mode 100644
index f657cef..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/MediaSession.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Copyright 2014, 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.
-*/
-
-package android.media.session;
-
-parcelable MediaSession.Token;
-parcelable MediaSession.QueueItem;
\ No newline at end of file
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaSession.java b/packages/MediaComponents/apex/java/android/media/session/MediaSession.java
deleted file mode 100644
index 3cbeff9..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/MediaSession.java
+++ /dev/null
@@ -1,1569 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.media.session;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.media.AudioAttributes;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.VolumeProvider;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.UserHandle;
-import android.service.media.MediaBrowserService;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Allows interaction with media controllers, volume keys, media buttons, and
- * transport controls.
- * <p>
- * A MediaSession should be created when an app wants to publish media playback
- * information or handle media keys. In general an app only needs one session
- * for all playback, though multiple sessions can be created to provide finer
- * grain controls of media.
- * <p>
- * Once a session is created the owner of the session may pass its
- * {@link #getSessionToken() session token} to other processes to allow them to
- * create a {@link MediaController} to interact with the session.
- * <p>
- * To receive commands, media keys, and other events a {@link Callback} must be
- * set with {@link #setCallback(Callback)} and {@link #setActive(boolean)
- * setActive(true)} must be called.
- * <p>
- * When an app is finished performing playback it must call {@link #release()}
- * to clean up the session and notify any controllers.
- * <p>
- * MediaSession objects are thread safe.
- */
-public final class MediaSession {
- private static final String TAG = "MediaSession";
-
- /**
- * Set this flag on the session to indicate that it can handle media button
- * events.
- * @deprecated This flag is no longer used. All media sessions are expected to handle media
- * button events now.
- */
- @Deprecated
- public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;
-
- /**
- * Set this flag on the session to indicate that it handles transport
- * control commands through its {@link Callback}.
- * @deprecated This flag is no longer used. All media sessions are expected to handle transport
- * controls now.
- */
- @Deprecated
- public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
-
- /**
- * System only flag for a session that needs to have priority over all other
- * sessions. This flag ensures this session will receive media button events
- * regardless of the current ordering in the system.
- *
- * @hide
- */
- public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
-
- /**
- * @hide
- */
- public static final int INVALID_UID = -1;
-
- /**
- * @hide
- */
- public static final int INVALID_PID = -1;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- FLAG_HANDLES_MEDIA_BUTTONS,
- FLAG_HANDLES_TRANSPORT_CONTROLS,
- FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
- public @interface SessionFlags { }
-
- private final Object mLock = new Object();
- private final int mMaxBitmapSize;
-
- private final MediaSession.Token mSessionToken;
- private final MediaController mController;
- private final ISession mBinder;
- private final CallbackStub mCbStub;
-
- // Do not change the name of mCallback. Support lib accesses this by using reflection.
- @UnsupportedAppUsage
- private CallbackMessageHandler mCallback;
- private VolumeProvider mVolumeProvider;
- private PlaybackState mPlaybackState;
-
- private boolean mActive = false;
-
- /**
- * Creates a new session. The session will automatically be registered with
- * the system but will not be published until {@link #setActive(boolean)
- * setActive(true)} is called. You must call {@link #release()} when
- * finished with the session.
- *
- * @param context The context to use to create the session.
- * @param tag A short name for debugging purposes.
- */
- public MediaSession(@NonNull Context context, @NonNull String tag) {
- this(context, tag, UserHandle.myUserId());
- }
-
- /**
- * Creates a new session as the specified user. To create a session as a
- * user other than your own you must hold the
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
- * permission.
- *
- * @param context The context to use to create the session.
- * @param tag A short name for debugging purposes.
- * @param userId The user id to create the session as.
- * @hide
- */
- public MediaSession(@NonNull Context context, @NonNull String tag, int userId) {
- if (context == null) {
- throw new IllegalArgumentException("context cannot be null.");
- }
- if (TextUtils.isEmpty(tag)) {
- throw new IllegalArgumentException("tag cannot be null or empty");
- }
- mMaxBitmapSize = context.getResources().getDimensionPixelSize(
- android.R.dimen.config_mediaMetadataBitmapMaxSize);
- mCbStub = new CallbackStub(this);
- MediaSessionManager manager = (MediaSessionManager) context
- .getSystemService(Context.MEDIA_SESSION_SERVICE);
- try {
- //TODO(b/119749862): Resolve hidden API usage. MediaSessioManager#createSession
- //mBinder = manager.createSession(mCbStub, tag, userId);
- mBinder = null; //TODO: remove this.
- mSessionToken = new Token(mBinder.getController());
- mController = new MediaController(context, mSessionToken);
- } catch (RemoteException e) {
- throw new RuntimeException("Remote error creating session.", e);
- }
- }
-
- /**
- * Set the callback to receive updates for the MediaSession. This includes
- * media button events and transport controls. The caller's thread will be
- * used to post updates.
- * <p>
- * Set the callback to null to stop receiving updates.
- *
- * @param callback The callback object
- */
- public void setCallback(@Nullable Callback callback) {
- setCallback(callback, null);
- }
-
- /**
- * Set the callback to receive updates for the MediaSession. This includes
- * media button events and transport controls.
- * <p>
- * Set the callback to null to stop receiving updates.
- *
- * @param callback The callback to receive updates on.
- * @param handler The handler that events should be posted on.
- */
- public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
- synchronized (mLock) {
- if (mCallback != null) {
- // We're updating the callback, clear the session from the old one.
- mCallback.mCallback.mSession = null;
- mCallback.removeCallbacksAndMessages(null);
- }
- if (callback == null) {
- mCallback = null;
- return;
- }
- if (handler == null) {
- handler = new Handler();
- }
- callback.mSession = this;
- CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
- callback);
- mCallback = msgHandler;
- }
- }
-
- /**
- * Set an intent for launching UI for this Session. This can be used as a
- * quick link to an ongoing media screen. The intent should be for an
- * activity that may be started using {@link Activity#startActivity(Intent)}.
- *
- * @param pi The intent to launch to show UI for this Session.
- */
- public void setSessionActivity(@Nullable PendingIntent pi) {
- try {
- mBinder.setLaunchPendingIntent(pi);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
- }
- }
-
- /**
- * Set a pending intent for your media button receiver to allow restarting
- * playback after the session has been stopped. If your app is started in
- * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
- * the pending intent.
- *
- * @param mbr The {@link PendingIntent} to send the media button event to.
- */
- public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
- try {
- mBinder.setMediaButtonReceiver(mbr);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
- }
- }
-
- /**
- * Set any flags for the session.
- *
- * @param flags The flags to set for this session.
- */
- public void setFlags(@SessionFlags int flags) {
- try {
- mBinder.setFlags(flags);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setFlags.", e);
- }
- }
-
- /**
- * Set the attributes for this session's audio. This will affect the
- * system's volume handling for this session. If
- * {@link #setPlaybackToRemote} was previously called it will stop receiving
- * volume commands and the system will begin sending volume changes to the
- * appropriate stream.
- * <p>
- * By default sessions use attributes for media.
- *
- * @param attributes The {@link AudioAttributes} for this session's audio.
- */
- public void setPlaybackToLocal(AudioAttributes attributes) {
- if (attributes == null) {
- throw new IllegalArgumentException("Attributes cannot be null for local playback.");
- }
- //TODO(b/119751592): Decide if AudioAttributes should be updated.
- /*
- try {
- mBinder.setPlaybackToLocal(attributes);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
- }
- */
- }
-
- /**
- * Configure this session to use remote volume handling. This must be called
- * to receive volume button events, otherwise the system will adjust the
- * appropriate stream volume for this session. If
- * {@link #setPlaybackToLocal} was previously called the system will stop
- * handling volume changes for this session and pass them to the volume
- * provider instead.
- *
- * @param volumeProvider The provider that will handle volume changes. May
- * not be null.
- */
- public void setPlaybackToRemote(@NonNull VolumeProvider volumeProvider) {
- if (volumeProvider == null) {
- throw new IllegalArgumentException("volumeProvider may not be null!");
- }
- synchronized (mLock) {
- mVolumeProvider = volumeProvider;
- }
- volumeProvider.setCallback(new VolumeProvider.Callback() {
- @Override
- public void onVolumeChanged(VolumeProvider volumeProvider) {
- notifyRemoteVolumeChanged(volumeProvider);
- }
- });
-
- try {
- mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
- volumeProvider.getMaxVolume());
- mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
- }
- }
-
- /**
- * Set if this session is currently active and ready to receive commands. If
- * set to false your session's controller may not be discoverable. You must
- * set the session to active before it can start receiving media button
- * events or transport commands.
- *
- * @param active Whether this session is active or not.
- */
- public void setActive(boolean active) {
- if (mActive == active) {
- return;
- }
- try {
- mBinder.setActive(active);
- mActive = active;
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setActive.", e);
- }
- }
-
- /**
- * Get the current active state of this session.
- *
- * @return True if the session is active, false otherwise.
- */
- public boolean isActive() {
- return mActive;
- }
-
- /**
- * Send a proprietary event to all MediaControllers listening to this
- * Session. It's up to the Controller/Session owner to determine the meaning
- * of any events.
- *
- * @param event The name of the event to send
- * @param extras Any extras included with the event
- */
- public void sendSessionEvent(@NonNull String event, @Nullable Bundle extras) {
- if (TextUtils.isEmpty(event)) {
- throw new IllegalArgumentException("event cannot be null or empty");
- }
- try {
- mBinder.sendEvent(event, extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error sending event", e);
- }
- }
-
- /**
- * This must be called when an app has finished performing playback. If
- * playback is expected to start again shortly the session can be left open,
- * but it must be released if your activity or service is being destroyed.
- */
- public void release() {
- try {
- mBinder.destroy();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error releasing session: ", e);
- }
- }
-
- /**
- * Retrieve a token object that can be used by apps to create a
- * {@link MediaController} for interacting with this session. The owner of
- * the session is responsible for deciding how to distribute these tokens.
- *
- * @return A token that can be used to create a MediaController for this
- * session
- */
- public @NonNull Token getSessionToken() {
- return mSessionToken;
- }
-
- /**
- * Get a controller for this session. This is a convenience method to avoid
- * having to cache your own controller in process.
- *
- * @return A controller for this session.
- */
- public @NonNull MediaController getController() {
- return mController;
- }
-
- /**
- * Update the current playback state.
- *
- * @param state The current state of playback
- */
- public void setPlaybackState(@Nullable PlaybackState state) {
- mPlaybackState = state;
- try {
- mBinder.setPlaybackState(state);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Dead object in setPlaybackState.", e);
- }
- }
-
- /**
- * Update the current metadata. New metadata can be created using
- * {@link android.media.MediaMetadata.Builder}. This operation may take time proportional to
- * the size of the bitmap to replace large bitmaps with a scaled down copy.
- *
- * @param metadata The new metadata
- * @see android.media.MediaMetadata.Builder#putBitmap
- */
- public void setMetadata(@Nullable MediaMetadata metadata) {
- long duration = -1;
- int fields = 0;
- MediaDescription description = null;
- if (metadata != null) {
- metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
- if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
- duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
- }
- fields = metadata.size();
- description = metadata.getDescription();
- }
- String metadataDescription = "size=" + fields + ", description=" + description;
-
- try {
- mBinder.setMetadata(metadata, duration, metadataDescription);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Dead object in setPlaybackState.", e);
- }
- }
-
- /**
- * Update the list of items in the play queue. It is an ordered list and
- * should contain the current item, and previous or upcoming items if they
- * exist. Specify null if there is no current play queue.
- * <p>
- * The queue should be of reasonable size. If the play queue is unbounded
- * within your app, it is better to send a reasonable amount in a sliding
- * window instead.
- *
- * @param queue A list of items in the play queue.
- */
- public void setQueue(@Nullable List<QueueItem> queue) {
- try {
- mBinder.setQueue(queue == null ? null : new MediaParceledListSlice<QueueItem>(queue));
- } catch (RemoteException e) {
- Log.wtf("Dead object in setQueue.", e);
- }
- }
-
- /**
- * Set the title of the play queue. The UI should display this title along
- * with the play queue itself.
- * e.g. "Play Queue", "Now Playing", or an album name.
- *
- * @param title The title of the play queue.
- */
- public void setQueueTitle(@Nullable CharSequence title) {
- try {
- mBinder.setQueueTitle(title);
- } catch (RemoteException e) {
- Log.wtf("Dead object in setQueueTitle.", e);
- }
- }
-
- /**
- * Set the style of rating used by this session. Apps trying to set the
- * rating should use this style. Must be one of the following:
- * <ul>
- * <li>{@link Rating#RATING_NONE}</li>
- * <li>{@link Rating#RATING_3_STARS}</li>
- * <li>{@link Rating#RATING_4_STARS}</li>
- * <li>{@link Rating#RATING_5_STARS}</li>
- * <li>{@link Rating#RATING_HEART}</li>
- * <li>{@link Rating#RATING_PERCENTAGE}</li>
- * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
- * </ul>
- */
- public void setRatingType(@Rating.Style int type) {
- try {
- mBinder.setRatingType(type);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in setRatingType.", e);
- }
- }
-
- /**
- * Set some extras that can be associated with the {@link MediaSession}. No assumptions should
- * be made as to how a {@link MediaController} will handle these extras.
- * Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
- *
- * @param extras The extras associated with the {@link MediaSession}.
- */
- public void setExtras(@Nullable Bundle extras) {
- try {
- mBinder.setExtras(extras);
- } catch (RemoteException e) {
- Log.wtf("Dead object in setExtras.", e);
- }
- }
-
- /**
- * Gets the controller information who sent the current request.
- * <p>
- * Note: This is only valid while in a request callback, such as {@link Callback#onPlay}.
- *
- * @throws IllegalStateException If this method is called outside of {@link Callback} methods.
- * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
- */
- public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
- if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
- throw new IllegalStateException(
- "This should be called inside of MediaSession.Callback methods");
- }
- return mCallback.mCurrentControllerInfo;
- }
-
- /**
- * Notify the system that the remote volume changed.
- *
- * @param provider The provider that is handling volume changes.
- * @hide
- */
- public void notifyRemoteVolumeChanged(VolumeProvider provider) {
- synchronized (mLock) {
- if (provider == null || provider != mVolumeProvider) {
- Log.w(TAG, "Received update from stale volume provider");
- return;
- }
- }
- try {
- mBinder.setCurrentVolume(provider.getCurrentVolume());
- } catch (RemoteException e) {
- Log.e(TAG, "Error in notifyVolumeChanged", e);
- }
- }
-
- /**
- * Returns the name of the package that sent the last media button, transport control, or
- * command from controllers and the system. This is only valid while in a request callback, such
- * as {@link Callback#onPlay}.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public String getCallingPackage() {
- if (mCallback != null && mCallback.mCurrentControllerInfo != null) {
- return mCallback.mCurrentControllerInfo.getPackageName();
- }
- return null;
- }
-
- private void dispatchPrepare(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
- }
-
- private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
- }
-
- private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
- }
-
- private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
- }
-
- private void dispatchPlay(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
- }
-
- private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
- }
-
- private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
- }
-
- private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
- }
-
- private void dispatchSkipToItem(RemoteUserInfo caller, long id) {
- postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
- }
-
- private void dispatchPause(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
- }
-
- private void dispatchStop(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
- }
-
- private void dispatchNext(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
- }
-
- private void dispatchPrevious(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
- }
-
- private void dispatchFastForward(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
- }
-
- private void dispatchRewind(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
- }
-
- private void dispatchSeekTo(RemoteUserInfo caller, long pos) {
- postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
- }
-
- private void dispatchRate(RemoteUserInfo caller, Rating rating) {
- postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
- }
-
- private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
- postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
- }
-
- private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
- postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
- }
-
- private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
- long delay) {
- postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
- mediaButtonIntent, null, delay);
- }
-
- private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
- postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
- }
-
- private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
- postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
- }
-
- private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
- ResultReceiver resultCb) {
- Command cmd = new Command(command, args, resultCb);
- postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
- }
-
- private void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
- postToCallbackDelayed(caller, what, obj, data, 0);
- }
-
- private void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
- long delay) {
- synchronized (mLock) {
- if (mCallback != null) {
- mCallback.post(caller, what, obj, data, delay);
- }
- }
- }
-
- /**
- * Return true if this is considered an active playback state.
- *
- * @hide
- */
- public static boolean isActiveState(int state) {
- switch (state) {
- case PlaybackState.STATE_FAST_FORWARDING:
- case PlaybackState.STATE_REWINDING:
- case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
- case PlaybackState.STATE_SKIPPING_TO_NEXT:
- case PlaybackState.STATE_BUFFERING:
- case PlaybackState.STATE_CONNECTING:
- case PlaybackState.STATE_PLAYING:
- return true;
- }
- return false;
- }
-
- /**
- * Represents an ongoing session. This may be passed to apps by the session
- * owner to allow them to create a {@link MediaController} to communicate with
- * the session.
- */
- public static final class Token implements Parcelable {
-
- private ISessionController mBinder;
-
- /**
- * @hide
- */
- public Token(ISessionController binder) {
- mBinder = binder;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongBinder(mBinder.asBinder());
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mBinder == null) ? 0 : mBinder.asBinder().hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Token other = (Token) obj;
- if (mBinder == null) {
- if (other.mBinder != null)
- return false;
- } else if (!mBinder.asBinder().equals(other.mBinder.asBinder()))
- return false;
- return true;
- }
-
- ISessionController getBinder() {
- return mBinder;
- }
-
- public static final Parcelable.Creator<Token> CREATOR
- = new Parcelable.Creator<Token>() {
- @Override
- public Token createFromParcel(Parcel in) {
- return new Token(ISessionController.Stub.asInterface(in.readStrongBinder()));
- }
-
- @Override
- public Token[] newArray(int size) {
- return new Token[size];
- }
- };
- }
-
- /**
- * Receives media buttons, transport controls, and commands from controllers
- * and the system. A callback may be set using {@link #setCallback}.
- */
- public abstract static class Callback {
-
- private MediaSession mSession;
- private CallbackMessageHandler mHandler;
- private boolean mMediaPlayPauseKeyPending;
-
- public Callback() {
- }
-
- /**
- * Called when a controller has sent a command to this session.
- * The owner of the session may handle custom commands but is not
- * required to.
- *
- * @param command The command name.
- * @param args Optional parameters for the command, may be null.
- * @param cb A result receiver to which a result may be sent by the command, may be null.
- */
- public void onCommand(@NonNull String command, @Nullable Bundle args,
- @Nullable ResultReceiver cb) {
- }
-
- /**
- * Called when a media button is pressed and this session has the
- * highest priority or a controller sends a media button event to the
- * session. The default behavior will call the relevant method if the
- * action for it was set.
- * <p>
- * The intent will be of type {@link Intent#ACTION_MEDIA_BUTTON} with a
- * KeyEvent in {@link Intent#EXTRA_KEY_EVENT}
- *
- * @param mediaButtonIntent an intent containing the KeyEvent as an
- * extra
- * @return True if the event was handled, false otherwise.
- */
- public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
- if (mSession != null && mHandler != null
- && Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) {
- KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
- if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
- PlaybackState state = mSession.mPlaybackState;
- long validActions = state == null ? 0 : state.getActions();
- switch (ke.getKeyCode()) {
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- if (ke.getRepeatCount() > 0) {
- // Consider long-press as a single tap.
- handleMediaPlayPauseKeySingleTapIfPending();
- } else if (mMediaPlayPauseKeyPending) {
- // Consider double tap as the next.
- mHandler.removeMessages(CallbackMessageHandler
- .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
- mMediaPlayPauseKeyPending = false;
- if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
- onSkipToNext();
- }
- } else {
- mMediaPlayPauseKeyPending = true;
- mSession.dispatchMediaButtonDelayed(
- mSession.getCurrentControllerInfo(),
- mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
- }
- return true;
- default:
- // If another key is pressed within double tap timeout, consider the
- // pending play/pause as a single tap to handle media keys in order.
- handleMediaPlayPauseKeySingleTapIfPending();
- break;
- }
-
- switch (ke.getKeyCode()) {
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- if ((validActions & PlaybackState.ACTION_PLAY) != 0) {
- onPlay();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- if ((validActions & PlaybackState.ACTION_PAUSE) != 0) {
- onPause();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
- onSkipToNext();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- if ((validActions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
- onSkipToPrevious();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_STOP:
- if ((validActions & PlaybackState.ACTION_STOP) != 0) {
- onStop();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
- if ((validActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
- onFastForward();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- if ((validActions & PlaybackState.ACTION_REWIND) != 0) {
- onRewind();
- return true;
- }
- break;
- }
- }
- }
- return false;
- }
-
- private void handleMediaPlayPauseKeySingleTapIfPending() {
- if (!mMediaPlayPauseKeyPending) {
- return;
- }
- mMediaPlayPauseKeyPending = false;
- mHandler.removeMessages(CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
- PlaybackState state = mSession.mPlaybackState;
- long validActions = state == null ? 0 : state.getActions();
- boolean isPlaying = state != null
- && state.getState() == PlaybackState.STATE_PLAYING;
- boolean canPlay = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
- | PlaybackState.ACTION_PLAY)) != 0;
- boolean canPause = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
- | PlaybackState.ACTION_PAUSE)) != 0;
- if (isPlaying && canPause) {
- onPause();
- } else if (!isPlaying && canPlay) {
- onPlay();
- }
- }
-
- /**
- * Override to handle requests to prepare playback. During the preparation, a session should
- * not hold audio focus in order to allow other sessions play seamlessly. The state of
- * playback should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is
- * done.
- */
- public void onPrepare() {
- }
-
- /**
- * Override to handle requests to prepare for playing a specific mediaId that was provided
- * by your app's {@link MediaBrowserService}. During the preparation, a session should not
- * hold audio focus in order to allow other sessions play seamlessly. The state of playback
- * should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done.
- * The playback of the prepared content should start in the implementation of
- * {@link #onPlay}. Override {@link #onPlayFromMediaId} to handle requests for starting
- * playback without preparation.
- */
- public void onPrepareFromMediaId(String mediaId, Bundle extras) {
- }
-
- /**
- * Override to handle requests to prepare playback from a search query. An empty query
- * indicates that the app may prepare any music. The implementation should attempt to make a
- * smart choice about what to play. During the preparation, a session should not hold audio
- * focus in order to allow other sessions play seamlessly. The state of playback should be
- * updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback
- * of the prepared content should start in the implementation of {@link #onPlay}. Override
- * {@link #onPlayFromSearch} to handle requests for starting playback without preparation.
- */
- public void onPrepareFromSearch(String query, Bundle extras) {
- }
-
- /**
- * Override to handle requests to prepare a specific media item represented by a URI.
- * During the preparation, a session should not hold audio focus in order to allow
- * other sessions play seamlessly. The state of playback should be updated to
- * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
- * The playback of the prepared content should start in the implementation of
- * {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
- * for starting playback without preparation.
- */
- public void onPrepareFromUri(Uri uri, Bundle extras) {
- }
-
- /**
- * Override to handle requests to begin playback.
- */
- public void onPlay() {
- }
-
- /**
- * Override to handle requests to begin playback from a search query. An
- * empty query indicates that the app may play any music. The
- * implementation should attempt to make a smart choice about what to
- * play.
- */
- public void onPlayFromSearch(String query, Bundle extras) {
- }
-
- /**
- * Override to handle requests to play a specific mediaId that was
- * provided by your app's {@link MediaBrowserService}.
- */
- public void onPlayFromMediaId(String mediaId, Bundle extras) {
- }
-
- /**
- * Override to handle requests to play a specific media item represented by a URI.
- */
- public void onPlayFromUri(Uri uri, Bundle extras) {
- }
-
- /**
- * Override to handle requests to play an item with a given id from the
- * play queue.
- */
- public void onSkipToQueueItem(long id) {
- }
-
- /**
- * Override to handle requests to pause playback.
- */
- public void onPause() {
- }
-
- /**
- * Override to handle requests to skip to the next media item.
- */
- public void onSkipToNext() {
- }
-
- /**
- * Override to handle requests to skip to the previous media item.
- */
- public void onSkipToPrevious() {
- }
-
- /**
- * Override to handle requests to fast forward.
- */
- public void onFastForward() {
- }
-
- /**
- * Override to handle requests to rewind.
- */
- public void onRewind() {
- }
-
- /**
- * Override to handle requests to stop playback.
- */
- public void onStop() {
- }
-
- /**
- * Override to handle requests to seek to a specific position in ms.
- *
- * @param pos New position to move to, in milliseconds.
- */
- public void onSeekTo(long pos) {
- }
-
- /**
- * Override to handle the item being rated.
- *
- * @param rating
- */
- public void onSetRating(@NonNull Rating rating) {
- }
-
- /**
- * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
- * performed.
- *
- * @param action The action that was originally sent in the
- * {@link PlaybackState.CustomAction}.
- * @param extras Optional extras specified by the {@link MediaController}.
- */
- public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
- }
- }
-
- /**
- * @hide
- */
- public static class CallbackStub extends ISessionCallback.Stub {
- private WeakReference<MediaSession> mMediaSession;
-
- public CallbackStub(MediaSession session) {
- mMediaSession = new WeakReference<>(session);
- }
-
- private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- return new RemoteUserInfo(packageName, pid, uid);
- }
-
- @Override
- public void onCommand(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid, caller),
- command, args, cb);
- }
- }
-
- @Override
- public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent,
- int sequenceNumber, ResultReceiver cb) {
- MediaSession session = mMediaSession.get();
- try {
- if (session != null) {
- session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, null),
- mediaButtonIntent);
- }
- } finally {
- if (cb != null) {
- cb.send(sequenceNumber, null);
- }
- }
- }
-
- @Override
- public void onMediaButtonFromController(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Intent mediaButtonIntent) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, caller),
- mediaButtonIntent);
- }
- }
-
- @Override
- public void onPrepare(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onPrepareFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId,
- Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrepareFromMediaId(
- createRemoteUserInfo(packageName, pid, uid, caller), mediaId, extras);
- }
- }
-
- @Override
- public void onPrepareFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query,
- Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrepareFromSearch(
- createRemoteUserInfo(packageName, pid, uid, caller), query, extras);
- }
- }
-
- @Override
- public void onPrepareFromUri(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Uri uri, Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrepareFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
- uri, extras);
- }
- }
-
- @Override
- public void onPlay(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onPlayFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId,
- Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPlayFromMediaId(createRemoteUserInfo(packageName, pid, uid, caller),
- mediaId, extras);
- }
- }
-
- @Override
- public void onPlayFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query,
- Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPlayFromSearch(createRemoteUserInfo(packageName, pid, uid, caller),
- query, extras);
- }
- }
-
- @Override
- public void onPlayFromUri(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Uri uri, Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPlayFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
- uri, extras);
- }
- }
-
- @Override
- public void onSkipToTrack(String packageName, int pid, int uid,
- ISessionControllerCallback caller, long id) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchSkipToItem(createRemoteUserInfo(packageName, pid, uid, caller), id);
- }
- }
-
- @Override
- public void onPause(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPause(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onStop(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchStop(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onNext(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchNext(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onPrevious(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onFastForward(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchFastForward(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onRewind(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onSeekTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, long pos) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchSeekTo(createRemoteUserInfo(packageName, pid, uid, caller), pos);
- }
- }
-
- @Override
- public void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
- Rating rating) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchRate(createRemoteUserInfo(packageName, pid, uid, caller), rating);
- }
- }
-
- @Override
- public void onCustomAction(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String action, Bundle args) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchCustomAction(createRemoteUserInfo(packageName, pid, uid, caller),
- action, args);
- }
- }
-
- @Override
- public void onAdjustVolume(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int direction) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchAdjustVolume(createRemoteUserInfo(packageName, pid, uid, caller),
- direction);
- }
- }
-
- @Override
- public void onSetVolumeTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int value) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchSetVolumeTo(createRemoteUserInfo(packageName, pid, uid, caller),
- value);
- }
- }
- }
-
- /**
- * A single item that is part of the play queue. It contains a description
- * of the item and its id in the queue.
- */
- public static final class QueueItem implements Parcelable {
- /**
- * This id is reserved. No items can be explicitly assigned this id.
- */
- public static final int UNKNOWN_ID = -1;
-
- private final MediaDescription mDescription;
- @UnsupportedAppUsage
- private final long mId;
-
- /**
- * Create a new {@link MediaSession.QueueItem}.
- *
- * @param description The {@link MediaDescription} for this item.
- * @param id An identifier for this item. It must be unique within the
- * play queue and cannot be {@link #UNKNOWN_ID}.
- */
- public QueueItem(MediaDescription description, long id) {
- if (description == null) {
- throw new IllegalArgumentException("Description cannot be null.");
- }
- if (id == UNKNOWN_ID) {
- throw new IllegalArgumentException("Id cannot be QueueItem.UNKNOWN_ID");
- }
- mDescription = description;
- mId = id;
- }
-
- private QueueItem(Parcel in) {
- mDescription = MediaDescription.CREATOR.createFromParcel(in);
- mId = in.readLong();
- }
-
- /**
- * Get the description for this item.
- */
- public MediaDescription getDescription() {
- return mDescription;
- }
-
- /**
- * Get the queue id for this item.
- */
- public long getQueueId() {
- return mId;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- mDescription.writeToParcel(dest, flags);
- dest.writeLong(mId);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Creator<MediaSession.QueueItem> CREATOR =
- new Creator<MediaSession.QueueItem>() {
-
- @Override
- public MediaSession.QueueItem createFromParcel(Parcel p) {
- return new MediaSession.QueueItem(p);
- }
-
- @Override
- public MediaSession.QueueItem[] newArray(int size) {
- return new MediaSession.QueueItem[size];
- }
- };
-
- @Override
- public String toString() {
- return "MediaSession.QueueItem {" +
- "Description=" + mDescription +
- ", Id=" + mId + " }";
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == null) {
- return false;
- }
-
- if (!(o instanceof QueueItem)) {
- return false;
- }
-
- final QueueItem item = (QueueItem) o;
- if (mId != item.mId) {
- return false;
- }
-
- if (!Objects.equals(mDescription, item.mDescription)) {
- return false;
- }
-
- return true;
- }
- }
-
- private static final class Command {
- public final String command;
- public final Bundle extras;
- public final ResultReceiver stub;
-
- public Command(String command, Bundle extras, ResultReceiver stub) {
- this.command = command;
- this.extras = extras;
- this.stub = stub;
- }
- }
-
- private class CallbackMessageHandler extends Handler {
- private static final int MSG_COMMAND = 1;
- private static final int MSG_MEDIA_BUTTON = 2;
- private static final int MSG_PREPARE = 3;
- private static final int MSG_PREPARE_MEDIA_ID = 4;
- private static final int MSG_PREPARE_SEARCH = 5;
- private static final int MSG_PREPARE_URI = 6;
- private static final int MSG_PLAY = 7;
- private static final int MSG_PLAY_MEDIA_ID = 8;
- private static final int MSG_PLAY_SEARCH = 9;
- private static final int MSG_PLAY_URI = 10;
- private static final int MSG_SKIP_TO_ITEM = 11;
- private static final int MSG_PAUSE = 12;
- private static final int MSG_STOP = 13;
- private static final int MSG_NEXT = 14;
- private static final int MSG_PREVIOUS = 15;
- private static final int MSG_FAST_FORWARD = 16;
- private static final int MSG_REWIND = 17;
- private static final int MSG_SEEK_TO = 18;
- private static final int MSG_RATE = 19;
- private static final int MSG_CUSTOM_ACTION = 20;
- private static final int MSG_ADJUST_VOLUME = 21;
- private static final int MSG_SET_VOLUME = 22;
- private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
-
- private MediaSession.Callback mCallback;
- private RemoteUserInfo mCurrentControllerInfo;
-
- public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
- super(looper);
- mCallback = callback;
- mCallback.mHandler = this;
- }
-
- public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
- Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
- Message msg = obtainMessage(what, objWithCaller);
- msg.setAsynchronous(true);
- msg.setData(data);
- if (delayMs > 0) {
- sendMessageDelayed(msg, delayMs);
- } else {
- sendMessage(msg);
- }
- }
-
- @Override
- public void handleMessage(Message msg) {
- mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
-
- VolumeProvider vp;
- Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
-
- switch (msg.what) {
- case MSG_COMMAND:
- Command cmd = (Command) obj;
- mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
- break;
- case MSG_MEDIA_BUTTON:
- mCallback.onMediaButtonEvent((Intent) obj);
- break;
- case MSG_PREPARE:
- mCallback.onPrepare();
- break;
- case MSG_PREPARE_MEDIA_ID:
- mCallback.onPrepareFromMediaId((String) obj, msg.getData());
- break;
- case MSG_PREPARE_SEARCH:
- mCallback.onPrepareFromSearch((String) obj, msg.getData());
- break;
- case MSG_PREPARE_URI:
- mCallback.onPrepareFromUri((Uri) obj, msg.getData());
- break;
- case MSG_PLAY:
- mCallback.onPlay();
- break;
- case MSG_PLAY_MEDIA_ID:
- mCallback.onPlayFromMediaId((String) obj, msg.getData());
- break;
- case MSG_PLAY_SEARCH:
- mCallback.onPlayFromSearch((String) obj, msg.getData());
- break;
- case MSG_PLAY_URI:
- mCallback.onPlayFromUri((Uri) obj, msg.getData());
- break;
- case MSG_SKIP_TO_ITEM:
- mCallback.onSkipToQueueItem((Long) obj);
- break;
- case MSG_PAUSE:
- mCallback.onPause();
- break;
- case MSG_STOP:
- mCallback.onStop();
- break;
- case MSG_NEXT:
- mCallback.onSkipToNext();
- break;
- case MSG_PREVIOUS:
- mCallback.onSkipToPrevious();
- break;
- case MSG_FAST_FORWARD:
- mCallback.onFastForward();
- break;
- case MSG_REWIND:
- mCallback.onRewind();
- break;
- case MSG_SEEK_TO:
- mCallback.onSeekTo((Long) obj);
- break;
- case MSG_RATE:
- mCallback.onSetRating((Rating) obj);
- break;
- case MSG_CUSTOM_ACTION:
- mCallback.onCustomAction((String) obj, msg.getData());
- break;
- case MSG_ADJUST_VOLUME:
- synchronized (mLock) {
- vp = mVolumeProvider;
- }
- if (vp != null) {
- vp.onAdjustVolume((int) obj);
- }
- break;
- case MSG_SET_VOLUME:
- synchronized (mLock) {
- vp = mVolumeProvider;
- }
- if (vp != null) {
- vp.onSetVolumeTo((int) obj);
- }
- break;
- case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
- mCallback.handleMediaPlayPauseKeySingleTapIfPending();
- break;
- }
- mCurrentControllerInfo = null;
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.aidl b/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.aidl
deleted file mode 100644
index c4250f0..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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.
-*/
-
-package android.media.session;
-
-parcelable ParcelableVolumeInfo;
diff --git a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.java b/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.java
deleted file mode 100644
index f59c975..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright 2014, 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.
- */
-
-package android.media.session;
-
-import android.media.AudioAttributes;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Convenience class for passing information about the audio configuration of a
- * session. The public implementation is {@link MediaController.PlaybackInfo}.
- *
- * @hide
- */
-public class ParcelableVolumeInfo implements Parcelable {
- public int volumeType;
- public AudioAttributes audioAttrs;
- public int controlType;
- public int maxVolume;
- public int currentVolume;
-
- public ParcelableVolumeInfo(int volumeType, AudioAttributes audioAttrs, int controlType,
- int maxVolume,
- int currentVolume) {
- this.volumeType = volumeType;
- this.audioAttrs = audioAttrs;
- this.controlType = controlType;
- this.maxVolume = maxVolume;
- this.currentVolume = currentVolume;
- }
-
- public ParcelableVolumeInfo(Parcel from) {
- volumeType = from.readInt();
- controlType = from.readInt();
- maxVolume = from.readInt();
- currentVolume = from.readInt();
- audioAttrs = AudioAttributes.CREATOR.createFromParcel(from);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(volumeType);
- dest.writeInt(controlType);
- dest.writeInt(maxVolume);
- dest.writeInt(currentVolume);
- audioAttrs.writeToParcel(dest, flags);
- }
-
-
- public static final Parcelable.Creator<ParcelableVolumeInfo> CREATOR
- = new Parcelable.Creator<ParcelableVolumeInfo>() {
- @Override
- public ParcelableVolumeInfo createFromParcel(Parcel in) {
- return new ParcelableVolumeInfo(in);
- }
-
- @Override
- public ParcelableVolumeInfo[] newArray(int size) {
- return new ParcelableVolumeInfo[size];
- }
- };
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.aidl b/packages/MediaComponents/apex/java/android/media/session/PlaybackState.aidl
deleted file mode 100644
index 0876ebd..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Copyright 2014, 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.
-*/
-
-package android.media.session;
-
-parcelable PlaybackState;
diff --git a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.java b/packages/MediaComponents/apex/java/android/media/session/PlaybackState.java
deleted file mode 100644
index ed4f9af..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.java
+++ /dev/null
@@ -1,1081 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-package android.media.session;
-
-import android.annotation.DrawableRes;
-import android.annotation.IntDef;
-import android.annotation.LongDef;
-import android.annotation.Nullable;
-import android.media.RemoteControlClient;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import java.util.ArrayList;
-import java.util.List;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Playback state for a {@link MediaSession}. This includes a state like
- * {@link PlaybackState#STATE_PLAYING}, the current playback position,
- * and the current control capabilities.
- */
-public final class PlaybackState implements Parcelable {
- private static final String TAG = "PlaybackState";
-
- /**
- * @hide
- */
- @LongDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
- ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
- ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
- ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
- ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
- @Retention(RetentionPolicy.SOURCE)
- public @interface Actions {}
-
- /**
- * Indicates this session supports the stop command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_STOP = 1 << 0;
-
- /**
- * Indicates this session supports the pause command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PAUSE = 1 << 1;
-
- /**
- * Indicates this session supports the play command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PLAY = 1 << 2;
-
- /**
- * Indicates this session supports the rewind command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_REWIND = 1 << 3;
-
- /**
- * Indicates this session supports the previous command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
-
- /**
- * Indicates this session supports the next command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
-
- /**
- * Indicates this session supports the fast forward command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_FAST_FORWARD = 1 << 6;
-
- /**
- * Indicates this session supports the set rating command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SET_RATING = 1 << 7;
-
- /**
- * Indicates this session supports the seek to command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SEEK_TO = 1 << 8;
-
- /**
- * Indicates this session supports the play/pause toggle command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PLAY_PAUSE = 1 << 9;
-
- /**
- * Indicates this session supports the play from media id command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10;
-
- /**
- * Indicates this session supports the play from search command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
-
- /**
- * Indicates this session supports the skip to queue item command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
-
- /**
- * Indicates this session supports the play from URI command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PLAY_FROM_URI = 1 << 13;
-
- /**
- * Indicates this session supports the prepare command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PREPARE = 1 << 14;
-
- /**
- * Indicates this session supports the prepare from media id command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15;
-
- /**
- * Indicates this session supports the prepare from search command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16;
-
- /**
- * Indicates this session supports the prepare from URI command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
-
- /**
- * @hide
- */
- @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
- STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
- STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM})
- @Retention(RetentionPolicy.SOURCE)
- public @interface State {}
-
- /**
- * This is the default playback state and indicates that no media has been
- * added yet, or the performer has been reset and has no content to play.
- *
- * @see Builder#setState(int, long, float)
- * @see Builder#setState(int, long, float, long)
- */
- public final static int STATE_NONE = 0;
-
- /**
- * State indicating this item is currently stopped.
- *
- * @see Builder#setState
- */
- public final static int STATE_STOPPED = 1;
-
- /**
- * State indicating this item is currently paused.
- *
- * @see Builder#setState
- */
- public final static int STATE_PAUSED = 2;
-
- /**
- * State indicating this item is currently playing.
- *
- * @see Builder#setState
- */
- public final static int STATE_PLAYING = 3;
-
- /**
- * State indicating this item is currently fast forwarding.
- *
- * @see Builder#setState
- */
- public final static int STATE_FAST_FORWARDING = 4;
-
- /**
- * State indicating this item is currently rewinding.
- *
- * @see Builder#setState
- */
- public final static int STATE_REWINDING = 5;
-
- /**
- * State indicating this item is currently buffering and will begin playing
- * when enough data has buffered.
- *
- * @see Builder#setState
- */
- public final static int STATE_BUFFERING = 6;
-
- /**
- * State indicating this item is currently in an error state. The error
- * message should also be set when entering this state.
- *
- * @see Builder#setState
- */
- public final static int STATE_ERROR = 7;
-
- /**
- * State indicating the class doing playback is currently connecting to a
- * new destination. Depending on the implementation you may return to the previous
- * state when the connection finishes or enter {@link #STATE_NONE}.
- * If the connection failed {@link #STATE_ERROR} should be used.
- *
- * @see Builder#setState
- */
- public final static int STATE_CONNECTING = 8;
-
- /**
- * State indicating the player is currently skipping to the previous item.
- *
- * @see Builder#setState
- */
- public final static int STATE_SKIPPING_TO_PREVIOUS = 9;
-
- /**
- * State indicating the player is currently skipping to the next item.
- *
- * @see Builder#setState
- */
- public final static int STATE_SKIPPING_TO_NEXT = 10;
-
- /**
- * State indicating the player is currently skipping to a specific item in
- * the queue.
- *
- * @see Builder#setState
- */
- public final static int STATE_SKIPPING_TO_QUEUE_ITEM = 11;
-
- /**
- * Use this value for the position to indicate the position is not known.
- */
- public final static long PLAYBACK_POSITION_UNKNOWN = -1;
-
- private final int mState;
- private final long mPosition;
- private final long mBufferedPosition;
- private final float mSpeed;
- private final long mActions;
- private List<PlaybackState.CustomAction> mCustomActions;
- private final CharSequence mErrorMessage;
- private final long mUpdateTime;
- private final long mActiveItemId;
- private final Bundle mExtras;
-
- private PlaybackState(int state, long position, long updateTime, float speed,
- long bufferedPosition, long transportControls,
- List<PlaybackState.CustomAction> customActions, long activeItemId,
- CharSequence error, Bundle extras) {
- mState = state;
- mPosition = position;
- mSpeed = speed;
- mUpdateTime = updateTime;
- mBufferedPosition = bufferedPosition;
- mActions = transportControls;
- mCustomActions = new ArrayList<>(customActions);
- mActiveItemId = activeItemId;
- mErrorMessage = error;
- mExtras = extras;
- }
-
- private PlaybackState(Parcel in) {
- mState = in.readInt();
- mPosition = in.readLong();
- mSpeed = in.readFloat();
- mUpdateTime = in.readLong();
- mBufferedPosition = in.readLong();
- mActions = in.readLong();
- mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
- mActiveItemId = in.readLong();
- mErrorMessage = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mExtras = in.readBundle();
- }
-
- @Override
- public String toString() {
- StringBuilder bob = new StringBuilder("PlaybackState {");
- bob.append("state=").append(mState);
- bob.append(", position=").append(mPosition);
- bob.append(", buffered position=").append(mBufferedPosition);
- bob.append(", speed=").append(mSpeed);
- bob.append(", updated=").append(mUpdateTime);
- bob.append(", actions=").append(mActions);
- bob.append(", custom actions=").append(mCustomActions);
- bob.append(", active item id=").append(mActiveItemId);
- bob.append(", error=").append(mErrorMessage);
- bob.append("}");
- return bob.toString();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mState);
- dest.writeLong(mPosition);
- dest.writeFloat(mSpeed);
- dest.writeLong(mUpdateTime);
- dest.writeLong(mBufferedPosition);
- dest.writeLong(mActions);
- dest.writeTypedList(mCustomActions);
- dest.writeLong(mActiveItemId);
- TextUtils.writeToParcel(mErrorMessage, dest, 0);
- dest.writeBundle(mExtras);
- }
-
- /**
- * Get the current state of playback. One of the following:
- * <ul>
- * <li> {@link PlaybackState#STATE_NONE}</li>
- * <li> {@link PlaybackState#STATE_STOPPED}</li>
- * <li> {@link PlaybackState#STATE_PLAYING}</li>
- * <li> {@link PlaybackState#STATE_PAUSED}</li>
- * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
- * <li> {@link PlaybackState#STATE_REWINDING}</li>
- * <li> {@link PlaybackState#STATE_BUFFERING}</li>
- * <li> {@link PlaybackState#STATE_ERROR}</li>
- * <li> {@link PlaybackState#STATE_CONNECTING}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
- * </ul>
- */
- @State
- public int getState() {
- return mState;
- }
-
- /**
- * Get the current playback position in ms.
- */
- public long getPosition() {
- return mPosition;
- }
-
- /**
- * Get the current buffered position in ms. This is the farthest playback
- * point that can be reached from the current position using only buffered
- * content.
- */
- public long getBufferedPosition() {
- return mBufferedPosition;
- }
-
- /**
- * Get the current playback speed as a multiple of normal playback. This
- * should be negative when rewinding. A value of 1 means normal playback and
- * 0 means paused.
- *
- * @return The current speed of playback.
- */
- public float getPlaybackSpeed() {
- return mSpeed;
- }
-
- /**
- * Get the current actions available on this session. This should use a
- * bitmask of the available actions.
- * <ul>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#ACTION_REWIND}</li>
- * <li> {@link PlaybackState#ACTION_PLAY}</li>
- * <li> {@link PlaybackState#ACTION_PAUSE}</li>
- * <li> {@link PlaybackState#ACTION_STOP}</li>
- * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
- * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
- * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
- * </ul>
- */
- @Actions
- public long getActions() {
- return mActions;
- }
-
- /**
- * Get the list of custom actions.
- */
- public List<PlaybackState.CustomAction> getCustomActions() {
- return mCustomActions;
- }
-
- /**
- * Get a user readable error message. This should be set when the state is
- * {@link PlaybackState#STATE_ERROR}.
- */
- public CharSequence getErrorMessage() {
- return mErrorMessage;
- }
-
- /**
- * Get the elapsed real time at which position was last updated. If the
- * position has never been set this will return 0;
- *
- * @return The last time the position was updated.
- */
- public long getLastPositionUpdateTime() {
- return mUpdateTime;
- }
-
- /**
- * Get the id of the currently active item in the queue. If there is no
- * queue or a queue is not supported by the session this will be
- * {@link MediaSession.QueueItem#UNKNOWN_ID}.
- *
- * @return The id of the currently active item in the queue or
- * {@link MediaSession.QueueItem#UNKNOWN_ID}.
- */
- public long getActiveQueueItemId() {
- return mActiveItemId;
- }
-
- /**
- * Get any custom extras that were set on this playback state.
- *
- * @return The extras for this state or null.
- */
- public @Nullable Bundle getExtras() {
- return mExtras;
- }
-
- /**
- * Get the {@link PlaybackState} state for the given
- * {@link RemoteControlClient} state.
- *
- * @param rccState The state used by {@link RemoteControlClient}.
- * @return The equivalent state used by {@link PlaybackState}.
- * @hide
- */
- public static int getStateFromRccState(int rccState) {
- switch (rccState) {
- case RemoteControlClient.PLAYSTATE_BUFFERING:
- return STATE_BUFFERING;
- case RemoteControlClient.PLAYSTATE_ERROR:
- return STATE_ERROR;
- case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
- return STATE_FAST_FORWARDING;
- //RemoteControlClient.PLAYSTATE_NONE is hidden
- case 0: //RemoteControlClient.PLAYSTATE_NONE:
- return STATE_NONE;
- case RemoteControlClient.PLAYSTATE_PAUSED:
- return STATE_PAUSED;
- case RemoteControlClient.PLAYSTATE_PLAYING:
- return STATE_PLAYING;
- case RemoteControlClient.PLAYSTATE_REWINDING:
- return STATE_REWINDING;
- case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
- return STATE_SKIPPING_TO_PREVIOUS;
- case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
- return STATE_SKIPPING_TO_NEXT;
- case RemoteControlClient.PLAYSTATE_STOPPED:
- return STATE_STOPPED;
- default:
- return -1;
- }
- }
-
- /**
- * Get the {@link RemoteControlClient} state for the given
- * {@link PlaybackState} state.
- *
- * @param state The state used by {@link PlaybackState}.
- * @return The equivalent state used by {@link RemoteControlClient}.
- * @hide
- */
- public static int getRccStateFromState(int state) {
- switch (state) {
- case STATE_BUFFERING:
- return RemoteControlClient.PLAYSTATE_BUFFERING;
- case STATE_ERROR:
- return RemoteControlClient.PLAYSTATE_ERROR;
- case STATE_FAST_FORWARDING:
- return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
- case STATE_NONE:
- //RemoteControlClient.PLAYSTATE_NONE is hidden
- return 0; //RemoteControlClient.PLAYSTATE_NONE;
- case STATE_PAUSED:
- return RemoteControlClient.PLAYSTATE_PAUSED;
- case STATE_PLAYING:
- return RemoteControlClient.PLAYSTATE_PLAYING;
- case STATE_REWINDING:
- return RemoteControlClient.PLAYSTATE_REWINDING;
- case STATE_SKIPPING_TO_PREVIOUS:
- return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
- case STATE_SKIPPING_TO_NEXT:
- return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
- case STATE_STOPPED:
- return RemoteControlClient.PLAYSTATE_STOPPED;
- default:
- return -1;
- }
- }
-
- /**
- * @hide
- */
- public static long getActionsFromRccControlFlags(int rccFlags) {
- long actions = 0;
- long flag = 1;
- while (flag <= rccFlags) {
- if ((flag & rccFlags) != 0) {
- actions |= getActionForRccFlag((int) flag);
- }
- flag = flag << 1;
- }
- return actions;
- }
-
- /**
- * @hide
- */
- public static int getRccControlFlagsFromActions(long actions) {
- int rccFlags = 0;
- long action = 1;
- while (action <= actions && action < Integer.MAX_VALUE) {
- if ((action & actions) != 0) {
- rccFlags |= getRccFlagForAction(action);
- }
- action = action << 1;
- }
- return rccFlags;
- }
-
- private static long getActionForRccFlag(int flag) {
- switch (flag) {
- case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
- return ACTION_SKIP_TO_PREVIOUS;
- case RemoteControlClient.FLAG_KEY_MEDIA_REWIND:
- return ACTION_REWIND;
- case RemoteControlClient.FLAG_KEY_MEDIA_PLAY:
- return ACTION_PLAY;
- case RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE:
- return ACTION_PLAY_PAUSE;
- case RemoteControlClient.FLAG_KEY_MEDIA_PAUSE:
- return ACTION_PAUSE;
- case RemoteControlClient.FLAG_KEY_MEDIA_STOP:
- return ACTION_STOP;
- case RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD:
- return ACTION_FAST_FORWARD;
- case RemoteControlClient.FLAG_KEY_MEDIA_NEXT:
- return ACTION_SKIP_TO_NEXT;
- case RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE:
- return ACTION_SEEK_TO;
- case RemoteControlClient.FLAG_KEY_MEDIA_RATING:
- return ACTION_SET_RATING;
- }
- return 0;
- }
-
- private static int getRccFlagForAction(long action) {
- // We only care about the lower set of actions that can map to rcc
- // flags.
- int testAction = action < Integer.MAX_VALUE ? (int) action : 0;
- switch (testAction) {
- case (int) ACTION_SKIP_TO_PREVIOUS:
- return RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
- case (int) ACTION_REWIND:
- return RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
- case (int) ACTION_PLAY:
- return RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
- case (int) ACTION_PLAY_PAUSE:
- return RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
- case (int) ACTION_PAUSE:
- return RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
- case (int) ACTION_STOP:
- return RemoteControlClient.FLAG_KEY_MEDIA_STOP;
- case (int) ACTION_FAST_FORWARD:
- return RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
- case (int) ACTION_SKIP_TO_NEXT:
- return RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
- case (int) ACTION_SEEK_TO:
- return RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
- case (int) ACTION_SET_RATING:
- return RemoteControlClient.FLAG_KEY_MEDIA_RATING;
- }
- return 0;
- }
-
- public static final Parcelable.Creator<PlaybackState> CREATOR =
- new Parcelable.Creator<PlaybackState>() {
- @Override
- public PlaybackState createFromParcel(Parcel in) {
- return new PlaybackState(in);
- }
-
- @Override
- public PlaybackState[] newArray(int size) {
- return new PlaybackState[size];
- }
- };
-
- /**
- * {@link PlaybackState.CustomAction CustomActions} can be used to extend the capabilities of
- * the standard transport controls by exposing app specific actions to
- * {@link MediaController MediaControllers}.
- */
- public static final class CustomAction implements Parcelable {
- private final String mAction;
- private final CharSequence mName;
- private final int mIcon;
- private final Bundle mExtras;
-
- /**
- * Use {@link PlaybackState.CustomAction.Builder#build()}.
- */
- private CustomAction(String action, CharSequence name, int icon, Bundle extras) {
- mAction = action;
- mName = name;
- mIcon = icon;
- mExtras = extras;
- }
-
- private CustomAction(Parcel in) {
- mAction = in.readString();
- mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mIcon = in.readInt();
- mExtras = in.readBundle();
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mAction);
- TextUtils.writeToParcel(mName, dest, flags);
- dest.writeInt(mIcon);
- dest.writeBundle(mExtras);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<PlaybackState.CustomAction> CREATOR
- = new Parcelable.Creator<PlaybackState.CustomAction>() {
-
- @Override
- public PlaybackState.CustomAction createFromParcel(Parcel p) {
- return new PlaybackState.CustomAction(p);
- }
-
- @Override
- public PlaybackState.CustomAction[] newArray(int size) {
- return new PlaybackState.CustomAction[size];
- }
- };
-
- /**
- * Returns the action of the {@link CustomAction}.
- *
- * @return The action of the {@link CustomAction}.
- */
- public String getAction() {
- return mAction;
- }
-
- /**
- * Returns the display name of this action. e.g. "Favorite"
- *
- * @return The display name of this {@link CustomAction}.
- */
- public CharSequence getName() {
- return mName;
- }
-
- /**
- * Returns the resource id of the icon in the {@link MediaSession MediaSession's} package.
- *
- * @return The resource id of the icon in the {@link MediaSession MediaSession's} package.
- */
- public int getIcon() {
- return mIcon;
- }
-
- /**
- * Returns extras which provide additional application-specific information about the
- * action, or null if none. These arguments are meant to be consumed by a
- * {@link MediaController} if it knows how to handle them.
- *
- * @return Optional arguments for the {@link CustomAction}.
- */
- public Bundle getExtras() {
- return mExtras;
- }
-
- @Override
- public String toString() {
- return "Action:" +
- "mName='" + mName +
- ", mIcon=" + mIcon +
- ", mExtras=" + mExtras;
- }
-
- /**
- * Builder for {@link CustomAction} objects.
- */
- public static final class Builder {
- private final String mAction;
- private final CharSequence mName;
- private final int mIcon;
- private Bundle mExtras;
-
- /**
- * Creates a {@link CustomAction} builder with the id, name, and icon set.
- *
- * @param action The action of the {@link CustomAction}.
- * @param name The display name of the {@link CustomAction}. This name will be displayed
- * along side the action if the UI supports it.
- * @param icon The icon resource id of the {@link CustomAction}. This resource id
- * must be in the same package as the {@link MediaSession}. It will be
- * displayed with the custom action if the UI supports it.
- */
- public Builder(String action, CharSequence name, @DrawableRes int icon) {
- if (TextUtils.isEmpty(action)) {
- throw new IllegalArgumentException(
- "You must specify an action to build a CustomAction.");
- }
- if (TextUtils.isEmpty(name)) {
- throw new IllegalArgumentException(
- "You must specify a name to build a CustomAction.");
- }
- if (icon == 0) {
- throw new IllegalArgumentException(
- "You must specify an icon resource id to build a CustomAction.");
- }
- mAction = action;
- mName = name;
- mIcon = icon;
- }
-
- /**
- * Set optional extras for the {@link CustomAction}. These extras are meant to be
- * consumed by a {@link MediaController} if it knows how to handle them.
- * Keys should be fully qualified (e.g. "com.example.MY_ARG") to avoid collisions.
- *
- * @param extras Optional extras for the {@link CustomAction}.
- * @return this.
- */
- public Builder setExtras(Bundle extras) {
- mExtras = extras;
- return this;
- }
-
- /**
- * Build and return the {@link CustomAction} instance with the specified values.
- *
- * @return A new {@link CustomAction} instance.
- */
- public CustomAction build() {
- return new CustomAction(mAction, mName, mIcon, mExtras);
- }
- }
- }
-
- /**
- * Builder for {@link PlaybackState} objects.
- */
- public static final class Builder {
- private final List<PlaybackState.CustomAction> mCustomActions = new ArrayList<>();
-
- private int mState;
- private long mPosition;
- private long mBufferedPosition;
- private float mSpeed;
- private long mActions;
- private CharSequence mErrorMessage;
- private long mUpdateTime;
- private long mActiveItemId = MediaSession.QueueItem.UNKNOWN_ID;
- private Bundle mExtras;
-
- /**
- * Creates an initially empty state builder.
- */
- public Builder() {
- }
-
- /**
- * Creates a builder with the same initial values as those in the from
- * state.
- *
- * @param from The state to use for initializing the builder.
- */
- public Builder(PlaybackState from) {
- if (from == null) {
- return;
- }
- mState = from.mState;
- mPosition = from.mPosition;
- mBufferedPosition = from.mBufferedPosition;
- mSpeed = from.mSpeed;
- mActions = from.mActions;
- if (from.mCustomActions != null) {
- mCustomActions.addAll(from.mCustomActions);
- }
- mErrorMessage = from.mErrorMessage;
- mUpdateTime = from.mUpdateTime;
- mActiveItemId = from.mActiveItemId;
- mExtras = from.mExtras;
- }
-
- /**
- * Set the current state of playback.
- * <p>
- * The position must be in ms and indicates the current playback
- * position within the item. If the position is unknown use
- * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
- * position the time at which the position was updated must be provided.
- * It is okay to use {@link SystemClock#elapsedRealtime()} if the
- * current position was just retrieved.
- * <p>
- * The speed is a multiple of normal playback and should be 0 when
- * paused and negative when rewinding. Normal playback speed is 1.0.
- * <p>
- * The state must be one of the following:
- * <ul>
- * <li> {@link PlaybackState#STATE_NONE}</li>
- * <li> {@link PlaybackState#STATE_STOPPED}</li>
- * <li> {@link PlaybackState#STATE_PLAYING}</li>
- * <li> {@link PlaybackState#STATE_PAUSED}</li>
- * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
- * <li> {@link PlaybackState#STATE_REWINDING}</li>
- * <li> {@link PlaybackState#STATE_BUFFERING}</li>
- * <li> {@link PlaybackState#STATE_ERROR}</li>
- * <li> {@link PlaybackState#STATE_CONNECTING}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
- * </ul>
- *
- * @param state The current state of playback.
- * @param position The position in the current item in ms.
- * @param playbackSpeed The current speed of playback as a multiple of
- * normal playback.
- * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
- * timebase that the position was updated at.
- * @return this
- */
- public Builder setState(@State int state, long position, float playbackSpeed,
- long updateTime) {
- mState = state;
- mPosition = position;
- mUpdateTime = updateTime;
- mSpeed = playbackSpeed;
- return this;
- }
-
- /**
- * Set the current state of playback.
- * <p>
- * The position must be in ms and indicates the current playback
- * position within the item. If the position is unknown use
- * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
- * the current {@link SystemClock#elapsedRealtime()}.
- * <p>
- * The speed is a multiple of normal playback and should be 0 when
- * paused and negative when rewinding. Normal playback speed is 1.0.
- * <p>
- * The state must be one of the following:
- * <ul>
- * <li> {@link PlaybackState#STATE_NONE}</li>
- * <li> {@link PlaybackState#STATE_STOPPED}</li>
- * <li> {@link PlaybackState#STATE_PLAYING}</li>
- * <li> {@link PlaybackState#STATE_PAUSED}</li>
- * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
- * <li> {@link PlaybackState#STATE_REWINDING}</li>
- * <li> {@link PlaybackState#STATE_BUFFERING}</li>
- * <li> {@link PlaybackState#STATE_ERROR}</li>
- * <li> {@link PlaybackState#STATE_CONNECTING}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
- * </ul>
- *
- * @param state The current state of playback.
- * @param position The position in the current item in ms.
- * @param playbackSpeed The current speed of playback as a multiple of
- * normal playback.
- * @return this
- */
- public Builder setState(@State int state, long position, float playbackSpeed) {
- return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
- }
-
- /**
- * Set the current actions available on this session. This should use a
- * bitmask of possible actions.
- * <ul>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#ACTION_REWIND}</li>
- * <li> {@link PlaybackState#ACTION_PLAY}</li>
- * <li> {@link PlaybackState#ACTION_PAUSE}</li>
- * <li> {@link PlaybackState#ACTION_STOP}</li>
- * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
- * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
- * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
- * </ul>
- *
- * @param actions The set of actions allowed.
- * @return this
- */
- public Builder setActions(@Actions long actions) {
- mActions = actions;
- return this;
- }
-
- /**
- * Add a custom action to the playback state. Actions can be used to
- * expose additional functionality to {@link MediaController
- * MediaControllers} beyond what is offered by the standard transport
- * controls.
- * <p>
- * e.g. start a radio station based on the current item or skip ahead by
- * 30 seconds.
- *
- * @param action An identifier for this action. It can be sent back to
- * the {@link MediaSession} through
- * {@link MediaController.TransportControls#sendCustomAction(String, Bundle)}.
- * @param name The display name for the action. If text is shown with
- * the action or used for accessibility, this is what should
- * be used.
- * @param icon The resource action of the icon that should be displayed
- * for the action. The resource should be in the package of
- * the {@link MediaSession}.
- * @return this
- */
- public Builder addCustomAction(String action, String name, int icon) {
- return addCustomAction(new PlaybackState.CustomAction(action, name, icon, null));
- }
-
- /**
- * Add a custom action to the playback state. Actions can be used to expose additional
- * functionality to {@link MediaController MediaControllers} beyond what is offered by the
- * standard transport controls.
- * <p>
- * An example of an action would be to start a radio station based on the current item
- * or to skip ahead by 30 seconds.
- *
- * @param customAction The custom action to add to the {@link PlaybackState}.
- * @return this
- */
- public Builder addCustomAction(PlaybackState.CustomAction customAction) {
- if (customAction == null) {
- throw new IllegalArgumentException(
- "You may not add a null CustomAction to PlaybackState.");
- }
- mCustomActions.add(customAction);
- return this;
- }
-
- /**
- * Set the current buffered position in ms. This is the farthest
- * playback point that can be reached from the current position using
- * only buffered content.
- *
- * @param bufferedPosition The position in ms that playback is buffered
- * to.
- * @return this
- */
- public Builder setBufferedPosition(long bufferedPosition) {
- mBufferedPosition = bufferedPosition;
- return this;
- }
-
- /**
- * Set the active item in the play queue by specifying its id. The
- * default value is {@link MediaSession.QueueItem#UNKNOWN_ID}
- *
- * @param id The id of the active item.
- * @return this
- */
- public Builder setActiveQueueItemId(long id) {
- mActiveItemId = id;
- return this;
- }
-
- /**
- * Set a user readable error message. This should be set when the state
- * is {@link PlaybackState#STATE_ERROR}.
- *
- * @param error The error message for display to the user.
- * @return this
- */
- public Builder setErrorMessage(CharSequence error) {
- mErrorMessage = error;
- return this;
- }
-
- /**
- * Set any custom extras to be included with the playback state.
- *
- * @param extras The extras to include.
- * @return this
- */
- public Builder setExtras(Bundle extras) {
- mExtras = extras;
- return this;
- }
-
- /**
- * Build and return the {@link PlaybackState} instance with these
- * values.
- *
- * @return A new state instance.
- */
- public PlaybackState build() {
- return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferedPosition,
- mActions, mCustomActions, mActiveItemId, mErrorMessage, mExtras);
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserService.aidl b/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserService.aidl
deleted file mode 100644
index 84f41f6..0000000
--- a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserService.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-
-package android.service.media;
-
-import android.content.res.Configuration;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * Media API allows clients to browse through hierarchy of a user’s media collection,
- * playback a specific media entry and interact with the now playing queue.
- * @hide
- */
-oneway interface IMediaBrowserService {
- void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
- void disconnect(IMediaBrowserServiceCallbacks callbacks);
-
- void addSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
- void removeSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
-
- void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks);
- void addSubscription(String uri, in IBinder token, in Bundle options,
- IMediaBrowserServiceCallbacks callbacks);
- void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks);
-}
diff --git a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
deleted file mode 100644
index 8dc480d..0000000
--- a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-
-package android.service.media;
-
-import android.graphics.Bitmap;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-
-/**
- * Media API allows clients to browse through hierarchy of a user’s media collection,
- * playback a specific media entry and interact with the now playing queue.
- * @hide
- */
-oneway interface IMediaBrowserServiceCallbacks {
- /**
- * Invoked when the connected has been established.
- * @param root The root media id for browsing.
- * @param session The {@link MediaSession.Token media session token} that can be used to control
- * the playback of the media app.
- * @param extra Extras returned by the media service.
- */
- void onConnect(String root, in MediaSession.Token session, in Bundle extras);
- void onConnectFailed();
- void onLoadChildren(String mediaId, in MediaParceledListSlice list);
- void onLoadChildrenWithOptions(String mediaId, in MediaParceledListSlice list,
- in Bundle options);
-}
diff --git a/packages/MediaComponents/apex/java/android/service/media/MediaBrowserService.java b/packages/MediaComponents/apex/java/android/service/media/MediaBrowserService.java
deleted file mode 100644
index 76c99b9..0000000
--- a/packages/MediaComponents/apex/java/android/service/media/MediaBrowserService.java
+++ /dev/null
@@ -1,856 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package android.service.media;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.UnsupportedAppUsage;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.media.MediaParceledListSlice;
-import android.media.browse.MediaBrowser;
-import android.media.browse.MediaBrowserUtils;
-import android.media.session.MediaSession;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.service.media.IMediaBrowserService;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.Pair;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Base class for media browser services.
- * <p>
- * Media browser services enable applications to browse media content provided by an application
- * and ask the application to start playing it. They may also be used to control content that
- * is already playing by way of a {@link MediaSession}.
- * </p>
- *
- * To extend this class, you must declare the service in your manifest file with
- * an intent filter with the {@link #SERVICE_INTERFACE} action.
- *
- * For example:
- * </p><pre>
- * <service android:name=".MyMediaBrowserService"
- * android:label="@string/service_name" >
- * <intent-filter>
- * <action android:name="android.media.browse.MediaBrowserService" />
- * </intent-filter>
- * </service>
- * </pre>
- *
- */
-public abstract class MediaBrowserService extends Service {
- private static final String TAG = "MediaBrowserService";
- private static final boolean DBG = false;
-
- /**
- * The {@link Intent} that must be declared as handled by the service.
- */
- @SdkConstant(SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
-
- /**
- * A key for passing the MediaItem to the ResultReceiver in getItem.
- * @hide
- */
- @UnsupportedAppUsage
- public static final String KEY_MEDIA_ITEM = "media_item";
-
- private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 1 << 0;
- private static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 1 << 1;
-
- private static final int RESULT_ERROR = -1;
- private static final int RESULT_OK = 0;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED,
- RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED })
- private @interface ResultFlags { }
-
- private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
- private ConnectionRecord mCurConnection;
- private final Handler mHandler = new Handler();
- private ServiceBinder mBinder;
- MediaSession.Token mSession;
-
- /**
- * All the info about a connection.
- */
- private class ConnectionRecord implements IBinder.DeathRecipient {
- String pkg;
- int uid;
- int pid;
- Bundle rootHints;
- IMediaBrowserServiceCallbacks callbacks;
- BrowserRoot root;
- HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
-
- @Override
- public void binderDied() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mConnections.remove(callbacks.asBinder());
- }
- });
- }
- }
-
- /**
- * Completion handler for asynchronous callback methods in {@link MediaBrowserService}.
- * <p>
- * Each of the methods that takes one of these to send the result must call
- * {@link #sendResult} to respond to the caller with the given results. If those
- * functions return without calling {@link #sendResult}, they must instead call
- * {@link #detach} before returning, and then may call {@link #sendResult} when
- * they are done. If more than one of those methods is called, an exception will
- * be thrown.
- *
- * @see #onLoadChildren
- * @see #onLoadItem
- */
- public class Result<T> {
- private Object mDebug;
- private boolean mDetachCalled;
- private boolean mSendResultCalled;
- @UnsupportedAppUsage
- private int mFlags;
-
- Result(Object debug) {
- mDebug = debug;
- }
-
- /**
- * Send the result back to the caller.
- */
- public void sendResult(T result) {
- if (mSendResultCalled) {
- throw new IllegalStateException("sendResult() called twice for: " + mDebug);
- }
- mSendResultCalled = true;
- onResultSent(result, mFlags);
- }
-
- /**
- * Detach this message from the current thread and allow the {@link #sendResult}
- * call to happen later.
- */
- public void detach() {
- if (mDetachCalled) {
- throw new IllegalStateException("detach() called when detach() had already"
- + " been called for: " + mDebug);
- }
- if (mSendResultCalled) {
- throw new IllegalStateException("detach() called when sendResult() had already"
- + " been called for: " + mDebug);
- }
- mDetachCalled = true;
- }
-
- boolean isDone() {
- return mDetachCalled || mSendResultCalled;
- }
-
- void setFlags(@ResultFlags int flags) {
- mFlags = flags;
- }
-
- /**
- * Called when the result is sent, after assertions about not being called twice
- * have happened.
- */
- void onResultSent(T result, @ResultFlags int flags) {
- }
- }
-
- private class ServiceBinder extends IMediaBrowserService.Stub {
- @Override
- public void connect(final String pkg, final Bundle rootHints,
- final IMediaBrowserServiceCallbacks callbacks) {
-
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- if (!isValidPackage(pkg, uid)) {
- throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
- + " package=" + pkg);
- }
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
-
- // Clear out the old subscriptions. We are getting new ones.
- mConnections.remove(b);
-
- final ConnectionRecord connection = new ConnectionRecord();
- connection.pkg = pkg;
- connection.pid = pid;
- connection.uid = uid;
- connection.rootHints = rootHints;
- connection.callbacks = callbacks;
-
- mCurConnection = connection;
- connection.root = MediaBrowserService.this.onGetRoot(pkg, uid, rootHints);
- mCurConnection = null;
-
- // If they didn't return something, don't allow this client.
- if (connection.root == null) {
- Log.i(TAG, "No root for client " + pkg + " from service "
- + getClass().getName());
- try {
- callbacks.onConnectFailed();
- } catch (RemoteException ex) {
- Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. "
- + "pkg=" + pkg);
- }
- } else {
- try {
- mConnections.put(b, connection);
- b.linkToDeath(connection, 0);
- if (mSession != null) {
- callbacks.onConnect(connection.root.getRootId(),
- mSession, connection.root.getExtras());
- }
- } catch (RemoteException ex) {
- Log.w(TAG, "Calling onConnect() failed. Dropping client. "
- + "pkg=" + pkg);
- mConnections.remove(b);
- }
- }
- }
- });
- }
-
- @Override
- public void disconnect(final IMediaBrowserServiceCallbacks callbacks) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
-
- // Clear out the old subscriptions. We are getting new ones.
- final ConnectionRecord old = mConnections.remove(b);
- if (old != null) {
- // TODO
- old.callbacks.asBinder().unlinkToDeath(old, 0);
- }
- }
- });
- }
-
- @Override
- public void addSubscriptionDeprecated(String id, IMediaBrowserServiceCallbacks callbacks) {
- // do-nothing
- }
-
- @Override
- public void addSubscription(final String id, final IBinder token, final Bundle options,
- final IMediaBrowserServiceCallbacks callbacks) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
-
- // Get the record for the connection
- final ConnectionRecord connection = mConnections.get(b);
- if (connection == null) {
- Log.w(TAG, "addSubscription for callback that isn't registered id="
- + id);
- return;
- }
-
- MediaBrowserService.this.addSubscription(id, connection, token, options);
- }
- });
- }
-
- @Override
- public void removeSubscriptionDeprecated(String id, IMediaBrowserServiceCallbacks callbacks) {
- // do-nothing
- }
-
- @Override
- public void removeSubscription(final String id, final IBinder token,
- final IMediaBrowserServiceCallbacks callbacks) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
-
- ConnectionRecord connection = mConnections.get(b);
- if (connection == null) {
- Log.w(TAG, "removeSubscription for callback that isn't registered id="
- + id);
- return;
- }
- if (!MediaBrowserService.this.removeSubscription(id, connection, token)) {
- Log.w(TAG, "removeSubscription called for " + id
- + " which is not subscribed");
- }
- }
- });
- }
-
- @Override
- public void getMediaItem(final String mediaId, final ResultReceiver receiver,
- final IMediaBrowserServiceCallbacks callbacks) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
- ConnectionRecord connection = mConnections.get(b);
- if (connection == null) {
- Log.w(TAG, "getMediaItem for callback that isn't registered id=" + mediaId);
- return;
- }
- performLoadItem(mediaId, connection, receiver);
- }
- });
- }
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- mBinder = new ServiceBinder();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- if (SERVICE_INTERFACE.equals(intent.getAction())) {
- return mBinder;
- }
- return null;
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- }
-
- /**
- * Called to get the root information for browsing by a particular client.
- * <p>
- * The implementation should verify that the client package has permission
- * to access browse media information before returning the root id; it
- * should return null if the client is not allowed to access this
- * information.
- * </p>
- *
- * @param clientPackageName The package name of the application which is
- * requesting access to browse media.
- * @param clientUid The uid of the application which is requesting access to
- * browse media.
- * @param rootHints An optional bundle of service-specific arguments to send
- * to the media browser service when connecting and retrieving the
- * root id for browsing, or null if none. The contents of this
- * bundle may affect the information returned when browsing.
- * @return The {@link BrowserRoot} for accessing this app's content or null.
- * @see BrowserRoot#EXTRA_RECENT
- * @see BrowserRoot#EXTRA_OFFLINE
- * @see BrowserRoot#EXTRA_SUGGESTED
- */
- public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
- int clientUid, @Nullable Bundle rootHints);
-
- /**
- * Called to get information about the children of a media item.
- * <p>
- * Implementations must call {@link Result#sendResult result.sendResult}
- * with the list of children. If loading the children will be an expensive
- * operation that should be performed on another thread,
- * {@link Result#detach result.detach} may be called before returning from
- * this function, and then {@link Result#sendResult result.sendResult}
- * called when the loading is complete.
- * </p><p>
- * In case the media item does not have any children, call {@link Result#sendResult}
- * with an empty list. When the given {@code parentId} is invalid, implementations must
- * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
- * {@link MediaBrowser.SubscriptionCallback#onError}.
- * </p>
- *
- * @param parentId The id of the parent media item whose children are to be
- * queried.
- * @param result The Result to send the list of children to.
- */
- public abstract void onLoadChildren(@NonNull String parentId,
- @NonNull Result<List<MediaBrowser.MediaItem>> result);
-
- /**
- * Called to get information about the children of a media item.
- * <p>
- * Implementations must call {@link Result#sendResult result.sendResult}
- * with the list of children. If loading the children will be an expensive
- * operation that should be performed on another thread,
- * {@link Result#detach result.detach} may be called before returning from
- * this function, and then {@link Result#sendResult result.sendResult}
- * called when the loading is complete.
- * </p><p>
- * In case the media item does not have any children, call {@link Result#sendResult}
- * with an empty list. When the given {@code parentId} is invalid, implementations must
- * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
- * {@link MediaBrowser.SubscriptionCallback#onError}.
- * </p>
- *
- * @param parentId The id of the parent media item whose children are to be
- * queried.
- * @param result The Result to send the list of children to.
- * @param options The bundle of service-specific arguments sent from the media
- * browser. The information returned through the result should be
- * affected by the contents of this bundle.
- */
- public void onLoadChildren(@NonNull String parentId,
- @NonNull Result<List<MediaBrowser.MediaItem>> result, @NonNull Bundle options) {
- // To support backward compatibility, when the implementation of MediaBrowserService doesn't
- // override onLoadChildren() with options, onLoadChildren() without options will be used
- // instead, and the options will be applied in the implementation of result.onResultSent().
- result.setFlags(RESULT_FLAG_OPTION_NOT_HANDLED);
- onLoadChildren(parentId, result);
- }
-
- /**
- * Called to get information about a specific media item.
- * <p>
- * Implementations must call {@link Result#sendResult result.sendResult}. If
- * loading the item will be an expensive operation {@link Result#detach
- * result.detach} may be called before returning from this function, and
- * then {@link Result#sendResult result.sendResult} called when the item has
- * been loaded.
- * </p><p>
- * When the given {@code itemId} is invalid, implementations must call
- * {@link Result#sendResult result.sendResult} with {@code null}.
- * </p><p>
- * The default implementation will invoke {@link MediaBrowser.ItemCallback#onError}.
- * </p>
- *
- * @param itemId The id for the specific
- * {@link android.media.browse.MediaBrowser.MediaItem}.
- * @param result The Result to send the item to.
- */
- public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
- result.setFlags(RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED);
- result.sendResult(null);
- }
-
- /**
- * Call to set the media session.
- * <p>
- * This should be called as soon as possible during the service's startup.
- * It may only be called once.
- *
- * @param token The token for the service's {@link MediaSession}.
- */
- public void setSessionToken(final MediaSession.Token token) {
- if (token == null) {
- throw new IllegalArgumentException("Session token may not be null.");
- }
- if (mSession != null) {
- throw new IllegalStateException("The session token has already been set.");
- }
- mSession = token;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Iterator<ConnectionRecord> iter = mConnections.values().iterator();
- while (iter.hasNext()){
- ConnectionRecord connection = iter.next();
- try {
- connection.callbacks.onConnect(connection.root.getRootId(), token,
- connection.root.getExtras());
- } catch (RemoteException e) {
- Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid.");
- iter.remove();
- }
- }
- }
- });
- }
-
- /**
- * Gets the session token, or null if it has not yet been created
- * or if it has been destroyed.
- */
- public @Nullable MediaSession.Token getSessionToken() {
- return mSession;
- }
-
- /**
- * Gets the root hints sent from the currently connected {@link MediaBrowser}.
- * The root hints are service-specific arguments included in an optional bundle sent to the
- * media browser service when connecting and retrieving the root id for browsing, or null if
- * none. The contents of this bundle may affect the information returned when browsing.
- *
- * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
- * {@link #onLoadChildren} or {@link #onLoadItem}.
- * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT
- * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
- * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
- */
- public final Bundle getBrowserRootHints() {
- if (mCurConnection == null) {
- throw new IllegalStateException("This should be called inside of onGetRoot or"
- + " onLoadChildren or onLoadItem methods");
- }
- return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints);
- }
-
- /**
- * Gets the browser information who sent the current request.
- *
- * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
- * {@link #onLoadChildren} or {@link #onLoadItem}.
- * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
- */
- public final RemoteUserInfo getCurrentBrowserInfo() {
- if (mCurConnection == null) {
- throw new IllegalStateException("This should be called inside of onGetRoot or"
- + " onLoadChildren or onLoadItem methods");
- }
- return new RemoteUserInfo(mCurConnection.pkg, mCurConnection.pid, mCurConnection.uid);
- }
-
- /**
- * Notifies all connected media browsers that the children of
- * the specified parent id have changed in some way.
- * This will cause browsers to fetch subscribed content again.
- *
- * @param parentId The id of the parent media item whose
- * children changed.
- */
- public void notifyChildrenChanged(@NonNull String parentId) {
- notifyChildrenChangedInternal(parentId, null);
- }
-
- /**
- * Notifies all connected media browsers that the children of
- * the specified parent id have changed in some way.
- * This will cause browsers to fetch subscribed content again.
- *
- * @param parentId The id of the parent media item whose
- * children changed.
- * @param options The bundle of service-specific arguments to send
- * to the media browser. The contents of this bundle may
- * contain the information about the change.
- */
- public void notifyChildrenChanged(@NonNull String parentId, @NonNull Bundle options) {
- if (options == null) {
- throw new IllegalArgumentException("options cannot be null in notifyChildrenChanged");
- }
- notifyChildrenChangedInternal(parentId, options);
- }
-
- private void notifyChildrenChangedInternal(final String parentId, final Bundle options) {
- if (parentId == null) {
- throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged");
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- for (IBinder binder : mConnections.keySet()) {
- ConnectionRecord connection = mConnections.get(binder);
- List<Pair<IBinder, Bundle>> callbackList =
- connection.subscriptions.get(parentId);
- if (callbackList != null) {
- for (Pair<IBinder, Bundle> callback : callbackList) {
- if (MediaBrowserUtils.hasDuplicatedItems(options, callback.second)) {
- performLoadChildren(parentId, connection, callback.second);
- }
- }
- }
- }
- }
- });
- }
-
- /**
- * Return whether the given package is one of the ones that is owned by the uid.
- */
- private boolean isValidPackage(String pkg, int uid) {
- if (pkg == null) {
- return false;
- }
- final PackageManager pm = getPackageManager();
- final String[] packages = pm.getPackagesForUid(uid);
- final int N = packages.length;
- for (int i=0; i<N; i++) {
- if (packages[i].equals(pkg)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Save the subscription and if it is a new subscription send the results.
- */
- private void addSubscription(String id, ConnectionRecord connection, IBinder token,
- Bundle options) {
- // Save the subscription
- List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
- if (callbackList == null) {
- callbackList = new ArrayList<>();
- }
- for (Pair<IBinder, Bundle> callback : callbackList) {
- if (token == callback.first
- && MediaBrowserUtils.areSameOptions(options, callback.second)) {
- return;
- }
- }
- callbackList.add(new Pair<>(token, options));
- connection.subscriptions.put(id, callbackList);
- // send the results
- performLoadChildren(id, connection, options);
- }
-
- /**
- * Remove the subscription.
- */
- private boolean removeSubscription(String id, ConnectionRecord connection, IBinder token) {
- if (token == null) {
- return connection.subscriptions.remove(id) != null;
- }
- boolean removed = false;
- List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
- if (callbackList != null) {
- Iterator<Pair<IBinder, Bundle>> iter = callbackList.iterator();
- while (iter.hasNext()){
- if (token == iter.next().first) {
- removed = true;
- iter.remove();
- }
- }
- if (callbackList.size() == 0) {
- connection.subscriptions.remove(id);
- }
- }
- return removed;
- }
-
- /**
- * Call onLoadChildren and then send the results back to the connection.
- * <p>
- * Callers must make sure that this connection is still connected.
- */
- private void performLoadChildren(final String parentId, final ConnectionRecord connection,
- final Bundle options) {
- final Result<List<MediaBrowser.MediaItem>> result
- = new Result<List<MediaBrowser.MediaItem>>(parentId) {
- @Override
- void onResultSent(List<MediaBrowser.MediaItem> list, @ResultFlags int flag) {
- if (mConnections.get(connection.callbacks.asBinder()) != connection) {
- if (DBG) {
- Log.d(TAG, "Not sending onLoadChildren result for connection that has"
- + " been disconnected. pkg=" + connection.pkg + " id=" + parentId);
- }
- return;
- }
-
- List<MediaBrowser.MediaItem> filteredList =
- (flag & RESULT_FLAG_OPTION_NOT_HANDLED) != 0
- ? applyOptions(list, options) : list;
- final MediaParceledListSlice<MediaBrowser.MediaItem> pls =
- filteredList == null ? null : new MediaParceledListSlice<>(filteredList);
- try {
- connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
- } catch (RemoteException ex) {
- // The other side is in the process of crashing.
- Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
- + " package=" + connection.pkg);
- }
- }
- };
-
- mCurConnection = connection;
- if (options == null) {
- onLoadChildren(parentId, result);
- } else {
- onLoadChildren(parentId, result, options);
- }
- mCurConnection = null;
-
- if (!result.isDone()) {
- throw new IllegalStateException("onLoadChildren must call detach() or sendResult()"
- + " before returning for package=" + connection.pkg + " id=" + parentId);
- }
- }
-
- private List<MediaBrowser.MediaItem> applyOptions(List<MediaBrowser.MediaItem> list,
- final Bundle options) {
- if (list == null) {
- return null;
- }
- int page = options.getInt(MediaBrowser.EXTRA_PAGE, -1);
- int pageSize = options.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
- if (page == -1 && pageSize == -1) {
- return list;
- }
- int fromIndex = pageSize * page;
- int toIndex = fromIndex + pageSize;
- if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
- return Collections.EMPTY_LIST;
- }
- if (toIndex > list.size()) {
- toIndex = list.size();
- }
- return list.subList(fromIndex, toIndex);
- }
-
- private void performLoadItem(String itemId, final ConnectionRecord connection,
- final ResultReceiver receiver) {
- final Result<MediaBrowser.MediaItem> result =
- new Result<MediaBrowser.MediaItem>(itemId) {
- @Override
- void onResultSent(MediaBrowser.MediaItem item, @ResultFlags int flag) {
- if (mConnections.get(connection.callbacks.asBinder()) != connection) {
- if (DBG) {
- Log.d(TAG, "Not sending onLoadItem result for connection that has"
- + " been disconnected. pkg=" + connection.pkg + " id=" + itemId);
- }
- return;
- }
- if ((flag & RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED) != 0) {
- receiver.send(RESULT_ERROR, null);
- return;
- }
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_MEDIA_ITEM, item);
- receiver.send(RESULT_OK, bundle);
- }
- };
-
- mCurConnection = connection;
- onLoadItem(itemId, result);
- mCurConnection = null;
-
- if (!result.isDone()) {
- throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
- + " before returning for id=" + itemId);
- }
- }
-
- /**
- * Contains information that the browser service needs to send to the client
- * when first connected.
- */
- public static final class BrowserRoot {
- /**
- * The lookup key for a boolean that indicates whether the browser service should return a
- * browser root for recently played media items.
- *
- * <p>When creating a media browser for a given media browser service, this key can be
- * supplied as a root hint for retrieving media items that are recently played.
- * If the media browser service can provide such media items, the implementation must return
- * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
- *
- * <p>The root hint may contain multiple keys.
- *
- * @see #EXTRA_OFFLINE
- * @see #EXTRA_SUGGESTED
- */
- public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
-
- /**
- * The lookup key for a boolean that indicates whether the browser service should return a
- * browser root for offline media items.
- *
- * <p>When creating a media browser for a given media browser service, this key can be
- * supplied as a root hint for retrieving media items that are can be played without an
- * internet connection.
- * If the media browser service can provide such media items, the implementation must return
- * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
- *
- * <p>The root hint may contain multiple keys.
- *
- * @see #EXTRA_RECENT
- * @see #EXTRA_SUGGESTED
- */
- public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
-
- /**
- * The lookup key for a boolean that indicates whether the browser service should return a
- * browser root for suggested media items.
- *
- * <p>When creating a media browser for a given media browser service, this key can be
- * supplied as a root hint for retrieving the media items suggested by the media browser
- * service. The list of media items passed in {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
- * is considered ordered by relevance, first being the top suggestion.
- * If the media browser service can provide such media items, the implementation must return
- * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
- *
- * <p>The root hint may contain multiple keys.
- *
- * @see #EXTRA_RECENT
- * @see #EXTRA_OFFLINE
- */
- public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-
- final private String mRootId;
- final private Bundle mExtras;
-
- /**
- * Constructs a browser root.
- * @param rootId The root id for browsing.
- * @param extras Any extras about the browser service.
- */
- public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) {
- if (rootId == null) {
- throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " +
- "Use null for BrowserRoot instead.");
- }
- mRootId = rootId;
- mExtras = extras;
- }
-
- /**
- * Gets the root id for browsing.
- */
- public String getRootId() {
- return mRootId;
- }
-
- /**
- * Gets any extras about the browser service.
- */
- public Bundle getExtras() {
- return mExtras;
- }
- }
-}
diff --git a/packages/OWNERS b/packages/OWNERS
deleted file mode 100644
index 3b9fd2b..0000000
--- a/packages/OWNERS
+++ /dev/null
@@ -1,9 +0,0 @@
-akersten@google.com
-dwkang@google.com
-hdmoon@google.com
-insun@google.com
-jaewan@google.com
-jinpark@google.com
-marcone@google.com
-sungsoo@google.com
-wjia@google.com
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index c0aa477..91b7587 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -38,7 +38,8 @@
libpowermanager \
libmediautils \
libmemunreachable \
- libmedia_helper
+ libmedia_helper \
+ libvibrator
LOCAL_STATIC_LIBRARIES := \
libcpustats \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0d6ef46..bc99099 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -27,6 +27,7 @@
#include <sys/time.h>
#include <sys/resource.h>
+#include <android/os/IExternalVibratorService.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
@@ -122,6 +123,21 @@
}
}
+// Keep a strong reference to external vibrator service
+static sp<os::IExternalVibratorService> sExternalVibratorService;
+
+static sp<os::IExternalVibratorService> getExternalVibratorService() {
+ if (sExternalVibratorService == 0) {
+ sp <IBinder> binder = defaultServiceManager()->getService(
+ String16("external_vibrator_service"));
+ if (binder != 0) {
+ sExternalVibratorService =
+ interface_cast<os::IExternalVibratorService>(binder);
+ }
+ }
+ return sExternalVibratorService;
+}
+
// ----------------------------------------------------------------------------
std::string formatToString(audio_format_t format) {
@@ -318,6 +334,27 @@
return ret;
}
+/* static */
+int AudioFlinger::onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration) {
+ sp<os::IExternalVibratorService> evs = getExternalVibratorService();
+ if (evs != 0) {
+ int32_t ret;
+ binder::Status status = evs->onExternalVibrationStart(*externalVibration, &ret);
+ if (status.isOk()) {
+ return ret;
+ }
+ }
+ return AudioMixer::HAPTIC_SCALE_NONE;
+}
+
+/* static */
+void AudioFlinger::onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration) {
+ sp<os::IExternalVibratorService> evs = getExternalVibratorService();
+ if (evs != 0) {
+ evs->onExternalVibrationStop(*externalVibration);
+ }
+}
+
static const char * const audio_interfaces[] = {
AUDIO_HARDWARE_MODULE_ID_PRIMARY,
AUDIO_HARDWARE_MODULE_ID_A2DP,
@@ -897,6 +934,40 @@
return NO_ERROR;
}
+status_t AudioFlinger::setMasterBalance(float balance)
+{
+ status_t ret = initCheck();
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+
+ // check calling permissions
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+
+ // check range
+ if (isnan(balance) || fabs(balance) > 1.f) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ // short cut.
+ if (mMasterBalance == balance) return NO_ERROR;
+
+ mMasterBalance = balance;
+
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
+ continue;
+ }
+ mPlaybackThreads.valueAt(i)->setMasterBalance(balance);
+ }
+
+ return NO_ERROR;
+}
+
status_t AudioFlinger::setMode(audio_mode_t mode)
{
status_t ret = initCheck();
@@ -1036,6 +1107,13 @@
return masterVolume_l();
}
+status_t AudioFlinger::getMasterBalance(float *balance) const
+{
+ Mutex::Autolock _l(mLock);
+ *balance = getMasterBalance_l();
+ return NO_ERROR; // if called through binder, may return a transactional error
+}
+
bool AudioFlinger::masterMute() const
{
Mutex::Autolock _l(mLock);
@@ -1047,6 +1125,11 @@
return mMasterVolume;
}
+float AudioFlinger::getMasterBalance_l() const
+{
+ return mMasterBalance;
+}
+
bool AudioFlinger::masterMute_l() const
{
return mMasterMute;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c1169d2..d8c0da5 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -30,6 +30,7 @@
#include <sys/types.h>
#include <limits.h>
+#include <android/os/BnExternalVibrationController.h>
#include <android-base/macros.h>
#include <cutils/atomic.h>
@@ -84,6 +85,8 @@
#include <private/media/AudioEffectShared.h>
#include <private/media/AudioTrackShared.h>
+#include <vibrator/ExternalVibration.h>
+
#include "android/media/BnAudioRecord.h"
namespace android {
@@ -137,6 +140,10 @@
virtual float masterVolume() const;
virtual bool masterMute() const;
+ // Balance value must be within -1.f (left only) to 1.f (right only) inclusive.
+ status_t setMasterBalance(float balance) override;
+ status_t getMasterBalance(float *balance) const override;
+
virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output);
virtual status_t setStreamMute(audio_stream_type_t stream, bool muted);
@@ -284,6 +291,9 @@
const sp<MmapStreamCallback>& callback,
sp<MmapStreamInterface>& interface,
audio_port_handle_t *handle);
+
+ static int onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration);
+ static void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration);
private:
// FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
static const size_t kLogMemorySize = 400 * 1024;
@@ -776,6 +786,7 @@
// member variables below are protected by mLock
float mMasterVolume;
bool mMasterMute;
+ float mMasterBalance = 0.f;
// end of variables protected by mLock
DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads;
@@ -793,6 +804,7 @@
Vector<AudioSessionRef*> mAudioSessionRefs;
float masterVolume_l() const;
+ float getMasterBalance_l() const;
bool masterMute_l() const;
audio_module_handle_t loadHwModule_l(const char *name);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index f328577..e78c98b 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -60,7 +60,6 @@
mSinkChannelCount(FCC_2),
mMixerBuffer(NULL),
mMixerBufferSize(0),
- mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT),
mMixerBufferState(UNDEFINED),
mFormat(Format_Invalid),
mSampleRate(0),
@@ -161,6 +160,7 @@
mOutputSink = current->mOutputSink;
mOutputSinkGen = current->mOutputSinkGen;
mSinkChannelMask = current->mSinkChannelMask;
+ mBalance.setChannelMask(mSinkChannelMask);
if (mOutputSink == NULL) {
mFormat = Format_Invalid;
mSampleRate = 0;
@@ -191,10 +191,6 @@
free(mSinkBuffer);
mSinkBuffer = NULL;
if (frameCount > 0 && mSampleRate > 0) {
- // The mixer produces either 16 bit PCM or float output, select
- // float output if the HAL supports higher than 16 bit precision.
- mMixerBufferFormat = mFormat.mFormat == AUDIO_FORMAT_PCM_16_BIT ?
- AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_FLOAT;
// FIXME new may block for unbounded time at internal mutex of the heap
// implementation; it would be better to have normal mixer allocate for us
// to avoid blocking here and to prevent possible priority inversion
@@ -295,6 +291,8 @@
(void *)(uintptr_t)mSinkChannelMask);
mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
(void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_INTENSITY,
+ (void *)(uintptr_t)fastTrack->mHapticIntensity);
mMixer->enable(name);
}
mGenerations[i] = fastTrack->mGeneration;
@@ -333,6 +331,8 @@
(void *)(uintptr_t)mSinkChannelMask);
mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED,
(void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled);
+ mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_INTENSITY,
+ (void *)(uintptr_t)fastTrack->mHapticIntensity);
// already enabled
}
mGenerations[i] = fastTrack->mGeneration;
@@ -471,6 +471,12 @@
mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount,
true /*limit*/);
}
+
+ // Balance must take effect after mono conversion.
+ // mBalance detects zero balance within the class for speed (not needed here).
+ mBalance.setBalance(mMasterBalance.load());
+ mBalance.process((float *)mMixerBuffer, frameCount);
+
// prepare the buffer used to write to sink
void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 1d332e0..c31d476 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -18,6 +18,7 @@
#define ANDROID_AUDIO_FAST_MIXER_H
#include <atomic>
+#include <audio_utils/Balance.h>
#include "FastThread.h"
#include "StateQueue.h"
#include "FastMixerState.h"
@@ -41,6 +42,8 @@
FastMixerStateQueue* sq();
virtual void setMasterMono(bool mono) { mMasterMono.store(mono); /* memory_order_seq_cst */ }
+ virtual void setMasterBalance(float balance) { mMasterBalance.store(balance); }
+ virtual float getMasterBalance() const { return mMasterBalance.load(); }
virtual void setBoottimeOffset(int64_t boottimeOffset) {
mBoottimeOffset.store(boottimeOffset); /* memory_order_seq_cst */
}
@@ -74,7 +77,7 @@
audio_channel_mask_t mSinkChannelMask;
void* mMixerBuffer; // mixer output buffer.
size_t mMixerBufferSize;
- audio_format_t mMixerBufferFormat; // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT).
+ static constexpr audio_format_t mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT;
uint32_t mAudioChannelCount; // audio channel count, excludes haptic channels.
@@ -89,8 +92,11 @@
ExtendedTimestamp mTimestamp;
int64_t mNativeFramesWrittenButNotPresented;
+ audio_utils::Balance mBalance;
+
// accessed without lock between multiple threads.
std::atomic_bool mMasterMono;
+ std::atomic<float> mMasterBalance{};
std::atomic_int_fast64_t mBoottimeOffset;
const audio_io_handle_t mThreadIoHandle; // parent thread id for debugging purposes
diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h
index 9d2a733..c27f2b7 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -19,6 +19,7 @@
#include <audio_utils/minifloat.h>
#include <system/audio.h>
+#include <media/AudioMixer.h>
#include <media/ExtendedAudioBufferProvider.h>
#include <media/nbaio/NBAIO.h>
#include <media/nblog/NBLog.h>
@@ -48,6 +49,8 @@
audio_format_t mFormat; // track format
int mGeneration; // increment when any field is assigned
bool mHapticPlaybackEnabled = false; // haptic playback is enabled or not
+ AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE; // intensity of
+ // haptic data
};
// Represents a single state of the fast mixer
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index d9f570d..bad3ca8 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -119,6 +119,15 @@
void setHapticPlaybackEnabled(bool hapticPlaybackEnabled) {
mHapticPlaybackEnabled = hapticPlaybackEnabled;
}
+ /** Return at what intensity to play haptics, used in mixer. */
+ AudioMixer::haptic_intensity_t getHapticIntensity() const { return mHapticIntensity; }
+ /** Set intensity of haptic playback, should be set after querying vibrator service. */
+ void setHapticIntensity(AudioMixer::haptic_intensity_t hapticIntensity) {
+ if (AudioMixer::isValidHapticIntensity(hapticIntensity)) {
+ mHapticIntensity = hapticIntensity;
+ }
+ }
+ sp<os::ExternalVibration> getExternalVibration() const { return mExternalVibration; }
protected:
// for numerous
@@ -197,6 +206,18 @@
sp<media::VolumeHandler> mVolumeHandler; // handles multiple VolumeShaper configs and operations
bool mHapticPlaybackEnabled = false; // indicates haptic playback enabled or not
+ // intensity to play haptic data
+ AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE;
+ class AudioVibrationController : public os::BnExternalVibrationController {
+ public:
+ explicit AudioVibrationController(Track* track) : mTrack(track) {}
+ binder::Status mute(/*out*/ bool *ret) override;
+ binder::Status unmute(/*out*/ bool *ret) override;
+ private:
+ Track* const mTrack;
+ };
+ sp<AudioVibrationController> mAudioVibrationController;
+ sp<os::ExternalVibration> mExternalVibration;
private:
// The following fields are only for fast tracks, and should be in a subclass
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 9f838a3..5a70864 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -38,6 +38,7 @@
#include <private/media/AudioTrackShared.h>
#include <private/android_filesystem_config.h>
+#include <audio_utils/Balance.h>
#include <audio_utils/channels.h>
#include <audio_utils/mono_blend.h>
#include <audio_utils/primitives.h>
@@ -2271,6 +2272,11 @@
}
}
+void AudioFlinger::PlaybackThread::setMasterBalance(float balance)
+{
+ mMasterBalance.store(balance);
+}
+
void AudioFlinger::PlaybackThread::setMasterMute(bool muted)
{
if (isDuplicating()) {
@@ -2358,15 +2364,23 @@
track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING;
}
- // Disable all haptic playback for all other active tracks when haptic playback is supported
- // and the track contains haptic channels. Enable haptic playback for current track.
- // TODO: Request actual haptic playback status from vibrator service
if ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
&& mHapticChannelMask != AUDIO_CHANNEL_NONE) {
- for (auto &t : mActiveTracks) {
- t->setHapticPlaybackEnabled(false);
+ // Unlock due to VibratorService will lock for this call and will
+ // call Tracks.mute/unmute which also require thread's lock.
+ mLock.unlock();
+ const int intensity = AudioFlinger::onExternalVibrationStart(
+ track->getExternalVibration());
+ mLock.lock();
+ // Haptic playback should be enabled by vibrator service.
+ if (track->getHapticPlaybackEnabled()) {
+ // Disable haptic playback of all active track to ensure only
+ // one track playing haptic if current track should play haptic.
+ for (const auto &t : mActiveTracks) {
+ t->setHapticPlaybackEnabled(false);
+ }
}
- track->setHapticPlaybackEnabled(true);
+ track->setHapticIntensity(intensity);
}
track->mResetDone = false;
@@ -2523,6 +2537,7 @@
mChannelMask);
}
mChannelCount = audio_channel_count_from_out_mask(mChannelMask);
+ mBalance.setChannelMask(mChannelMask);
// Get actual HAL format.
status_t result = mOutput->stream->getFormat(&mHALFormat);
@@ -2642,7 +2657,7 @@
free(mMixerBuffer);
mMixerBuffer = NULL;
if (mMixerBufferEnabled) {
- mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT; // also valid: AUDIO_FORMAT_PCM_16_BIT.
+ mMixerBufferFormat = AUDIO_FORMAT_PCM_FLOAT; // no longer valid: AUDIO_FORMAT_PCM_16_BIT.
mMixerBufferSize = mNormalFrameCount * mChannelCount
* audio_bytes_per_sample(mMixerBufferFormat);
(void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
@@ -3531,6 +3546,14 @@
true /*limit*/);
}
+ if (!hasFastMixer()) {
+ // Balance must take effect after mono conversion.
+ // We do it here if there is no FastMixer.
+ // mBalance detects zero balance within the class for speed (not needed here).
+ mBalance.setBalance(mMasterBalance.load());
+ mBalance.process((float *)mMixerBuffer, mNormalFrameCount);
+ }
+
memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
mNormalFrameCount * (mChannelCount + mHapticChannelCount));
@@ -3585,6 +3608,14 @@
true /*limit*/);
}
+ if (!hasFastMixer()) {
+ // Balance must take effect after mono conversion.
+ // We do it here if there is no FastMixer.
+ // mBalance detects zero balance within the class for speed (not needed here).
+ mBalance.setBalance(mMasterBalance.load());
+ mBalance.process((float *)mEffectBuffer, mNormalFrameCount);
+ }
+
memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
mNormalFrameCount * (mChannelCount + mHapticChannelCount));
// The sample data is partially interleaved when haptic channels exist,
@@ -3760,7 +3791,6 @@
// removeTracks_l() must be called with ThreadBase::mLock held
void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tracksToRemove)
{
- bool enabledHapticTracksRemoved = false;
for (const auto& track : tracksToRemove) {
mActiveTracks.remove(track);
ALOGV("%s(%d): removing track on session %d", __func__, track->id(), track->sessionId());
@@ -3782,17 +3812,13 @@
// remove from our tracks vector
removeTrack_l(track);
}
- enabledHapticTracksRemoved |= track->getHapticPlaybackEnabled();
- }
- // If the thread supports haptic playback and the track playing haptic data was removed,
- // enable haptic playback on the first active track that contains haptic channels.
- // TODO: Query vibrator service to know which track should enable haptic playback.
- if (enabledHapticTracksRemoved && mHapticChannelMask != AUDIO_CHANNEL_NONE) {
- for (auto &t : mActiveTracks) {
- if (t->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) {
- t->setHapticPlaybackEnabled(true);
- break;
- }
+ if ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
+ && mHapticChannelCount > 0) {
+ mLock.unlock();
+ // Unlock due to VibratorService will lock for this call and will
+ // call Tracks.mute/unmute which also require thread's lock.
+ AudioFlinger::onExternalVibrationStop(track->getExternalVibration());
+ mLock.lock();
}
}
}
@@ -3985,6 +4011,7 @@
// mPipeSink below
// mNormalSink below
{
+ setMasterBalance(audioFlinger->getMasterBalance_l());
ALOGV("MixerThread() id=%d device=%#x type=%d", id, device, type);
ALOGV("mSampleRate=%u, mChannelMask=%#x, mChannelCount=%u, mFormat=%#x, mFrameSize=%zu, "
"mFrameCount=%zu, mNormalFrameCount=%zu",
@@ -4615,6 +4642,7 @@
fastTrack->mChannelMask = track->mChannelMask;
fastTrack->mFormat = track->mFormat;
fastTrack->mHapticPlaybackEnabled = track->getHapticPlaybackEnabled();
+ fastTrack->mHapticIntensity = track->getHapticIntensity();
fastTrack->mGeneration++;
state->mTrackMask |= 1 << j;
didModify = true;
@@ -4937,6 +4965,10 @@
trackId,
AudioMixer::TRACK,
AudioMixer::HAPTIC_ENABLED, (void *)(uintptr_t)track->getHapticPlaybackEnabled());
+ mAudioMixer->setParameter(
+ trackId,
+ AudioMixer::TRACK,
+ AudioMixer::HAPTIC_INTENSITY, (void *)(uintptr_t)track->getHapticIntensity());
// reset retry count
track->mRetryCount = kMaxTrackRetries;
@@ -5266,6 +5298,9 @@
dprintf(fd, " Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
dprintf(fd, " AudioMixer tracks: %s\n", mAudioMixer->trackNames().c_str());
dprintf(fd, " Master mono: %s\n", mMasterMono ? "on" : "off");
+ dprintf(fd, " Master balance: %f (%s)\n", mMasterBalance.load(),
+ (hasFastMixer() ? std::to_string(mFastMixer->getMasterBalance())
+ : mBalance.toString()).c_str());
const double latencyMs = mTimestamp.getOutputServerLatencyMs(mSampleRate);
if (latencyMs != 0.) {
dprintf(fd, " NormalMixer latency ms: %.2lf\n", latencyMs);
@@ -5333,12 +5368,30 @@
ThreadBase::type_t type, bool systemReady)
: PlaybackThread(audioFlinger, output, id, device, type, systemReady)
{
+ setMasterBalance(audioFlinger->getMasterBalance_l());
}
AudioFlinger::DirectOutputThread::~DirectOutputThread()
{
}
+void AudioFlinger::DirectOutputThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+ PlaybackThread::dumpInternals(fd, args);
+ dprintf(fd, " Master balance: %f Left: %f Right: %f\n",
+ mMasterBalance.load(), mMasterBalanceLeft, mMasterBalanceRight);
+}
+
+void AudioFlinger::DirectOutputThread::setMasterBalance(float balance)
+{
+ Mutex::Autolock _l(mLock);
+ if (mMasterBalance != balance) {
+ mMasterBalance.store(balance);
+ mBalance.computeStereoBalance(balance, &mMasterBalanceLeft, &mMasterBalanceRight);
+ broadcast_l();
+ }
+}
+
void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTrack)
{
float left, right;
@@ -5362,12 +5415,12 @@
if (left > GAIN_FLOAT_UNITY) {
left = GAIN_FLOAT_UNITY;
}
- left *= v;
+ left *= v * mMasterBalanceLeft; // DirectOutputThread balance applied as track volume
right = float_from_gain(gain_minifloat_unpack_right(vlr));
if (right > GAIN_FLOAT_UNITY) {
right = GAIN_FLOAT_UNITY;
}
- right *= v;
+ right *= v * mMasterBalanceRight;
}
if (lastTrack) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8b8222c..1131b26 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -733,6 +733,7 @@
// VolumeInterface
virtual void setMasterVolume(float value);
+ virtual void setMasterBalance(float balance);
virtual void setMasterMute(bool muted);
virtual void setStreamVolume(audio_stream_type_t stream, float value);
virtual void setStreamMute(audio_stream_type_t stream, bool muted);
@@ -1027,6 +1028,8 @@
AudioStreamOut *mOutput;
float mMasterVolume;
+ std::atomic<float> mMasterBalance{};
+ audio_utils::Balance mBalance;
nsecs_t mLastWriteTime;
int mNumWrites;
int mNumDelayedWrites;
@@ -1199,6 +1202,13 @@
// Blending with limiter is not idempotent,
// and blending without limiter is idempotent but inefficient to do twice.
virtual bool requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
+
+ void setMasterBalance(float balance) override {
+ mMasterBalance.store(balance);
+ if (hasFastMixer()) {
+ mFastMixer->setMasterBalance(balance);
+ }
+ }
};
class DirectOutputThread : public PlaybackThread {
@@ -1216,8 +1226,13 @@
virtual bool checkForNewParameter_l(const String8& keyValuePair,
status_t& status);
+
+ void dumpInternals(int fd, const Vector<String16>& args) override;
+
virtual void flushHw_l();
+ void setMasterBalance(float balance) override;
+
protected:
virtual uint32_t activeSleepTimeUs() const;
virtual uint32_t idleSleepTimeUs() const;
@@ -1245,6 +1260,10 @@
wp<Track> mPreviousTrack; // used to detect track switch
+ // This must be initialized for initial condition of mMasterBalance = 0 (disabled).
+ float mMasterBalanceLeft = 1.f;
+ float mMasterBalanceRight = 1.f;
+
public:
virtual bool hasFastMixer() const { return false; }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index d23d19d..22d34b2 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -451,6 +451,12 @@
mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
+ "_" + std::to_string(mId));
#endif
+
+ if (channelMask & AUDIO_CHANNEL_HAPTIC_ALL) {
+ mAudioVibrationController = new AudioVibrationController(this);
+ mExternalVibration = new os::ExternalVibration(
+ mUid, "" /* pkg */, mAttr, mAudioVibrationController);
+ }
}
AudioFlinger::PlaybackThread::Track::~Track()
@@ -1336,6 +1342,40 @@
mServerLatencyMs.store(latencyMs);
}
+binder::Status AudioFlinger::PlaybackThread::Track::AudioVibrationController::mute(
+ /*out*/ bool *ret) {
+ *ret = false;
+ sp<ThreadBase> thread = mTrack->mThread.promote();
+ if (thread != 0) {
+ // Lock for updating mHapticPlaybackEnabled.
+ Mutex::Autolock _l(thread->mLock);
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ if ((mTrack->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
+ && playbackThread->mHapticChannelCount > 0) {
+ mTrack->setHapticPlaybackEnabled(false);
+ *ret = true;
+ }
+ }
+ return binder::Status::ok();
+}
+
+binder::Status AudioFlinger::PlaybackThread::Track::AudioVibrationController::unmute(
+ /*out*/ bool *ret) {
+ *ret = false;
+ sp<ThreadBase> thread = mTrack->mThread.promote();
+ if (thread != 0) {
+ // Lock for updating mHapticPlaybackEnabled.
+ Mutex::Autolock _l(thread->mLock);
+ PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
+ if ((mTrack->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
+ && playbackThread->mHapticChannelCount > 0) {
+ mTrack->setHapticPlaybackEnabled(true);
+ *ret = true;
+ }
+ }
+ return binder::Status::ok();
+}
+
// ----------------------------------------------------------------------------
#undef LOG_TAG
#define LOG_TAG "AF::OutputTrack"
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 3b9411a..cd10c82 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -411,11 +411,11 @@
if ((rule == RULE_EXCLUDE_UID || rule == RULE_MATCH_UID)
&& uid == mix->mCriteria[j].mValue.mUid) {
foundUidRule = true;
- criteriaToRemove.push_back(j);
+ criteriaToRemove.insert(criteriaToRemove.begin(), j);
}
}
if (foundUidRule) {
- for (size_t j = criteriaToRemove.size() - 1; j >= 0; j--) {
+ for (size_t j = 0; j < criteriaToRemove.size(); j++) {
mix->mCriteria.removeAt(criteriaToRemove[j]);
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index dc5b238..4cb1e17 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -129,7 +129,7 @@
ssize_t DeviceVector::indexOf(const sp<DeviceDescriptor>& item) const
{
for (size_t i = 0; i < size(); i++) {
- if (item->equals(itemAt(i))) {
+ if (itemAt(i)->equals(item)) { // item may be null sp<>, i.e. AUDIO_DEVICE_NONE
return i;
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 85d9bce..e0b233d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -332,10 +332,8 @@
if (moduleDevice) {
if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
moduleDevice->setEncodedFormat(encodedFormat);
- if (moduleDevice->address() != devAddress) {
- moduleDevice->setAddress(devAddress);
- }
}
+ moduleDevice->setAddress(devAddress);
if (allowToCreate) {
moduleDevice->attach(hwModule);
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index cf9c298..d7c7b4d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -555,7 +555,6 @@
muteWaitMs = setOutputDevices(mPrimaryOutput, rxDevices, true, delayMs);
} else { // create RX path audio patch
mCallRxPatch = createTelephonyPatch(true /*isRx*/, rxDevices.itemAt(0), delayMs);
- ALOG_ASSERT(createTxPatch, "No Tx Patch will be created, nor legacy routing done");
}
if (createTxPatch) { // create TX path audio patch
mCallTxPatch = createTelephonyPatch(false /*isRx*/, txSourceDevice, delayMs);
@@ -5063,7 +5062,7 @@
}
// If we are not in call and no client is active on this input, this methods returns
- // AUDIO_DEVICE_NONE, causing the patch on the input stream to be released.
+ // a null sp<>, causing the patch on the input stream to be released.
audio_attributes_t attributes = inputDesc->getHighestPriorityAttributes();
if (attributes.source == AUDIO_SOURCE_DEFAULT && isInCall()) {
attributes.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 49c541c..45fb174 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -525,7 +525,7 @@
static constexpr char kAudioPolicyActiveDevice[] =
"android.media.audiopolicy.active.device";
- MediaAnalyticsItem *item = new MediaAnalyticsItem(kAudioPolicy);
+ MediaAnalyticsItem *item = MediaAnalyticsItem::create(kAudioPolicy);
if (item != NULL) {
item->setInt32(kAudioPolicyStatus, status);
diff --git a/services/mediaanalytics/Android.bp b/services/mediaanalytics/Android.bp
new file mode 100644
index 0000000..c93c120
--- /dev/null
+++ b/services/mediaanalytics/Android.bp
@@ -0,0 +1,49 @@
+// Media Statistics service
+//
+
+cc_binary {
+ name: "mediametrics",
+
+ srcs: [
+ "main_mediametrics.cpp",
+ "MediaAnalyticsService.cpp",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libmedia",
+ "libutils",
+ "libbinder",
+ "libdl",
+ "libgui",
+ "libmedia",
+ "libmediautils",
+ "libmediametrics",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+
+ static_libs: ["libregistermsext"],
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright/include",
+ "frameworks/av/media/libstagefright/rtsp",
+ "frameworks/av/media/libstagefright/webm",
+ "frameworks/av/include/media",
+ "frameworks/av/include/camera",
+ "frameworks/native/include/media/openmax",
+ "frameworks/native/include/media/hardware",
+ "external/tremolo/Tremolo",
+ ],
+
+ init_rc: ["mediametrics.rc"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wno-error=deprecated-declarations",
+ ],
+ clang: true,
+
+}
diff --git a/services/mediaanalytics/Android.mk b/services/mediaanalytics/Android.mk
deleted file mode 100644
index 5b20e61..0000000
--- a/services/mediaanalytics/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-# Media Statistics service
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- main_mediametrics.cpp \
- MediaAnalyticsService.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
- libmedia \
- libutils \
- libbinder \
- libdl \
- libgui \
- libmedia \
- libmediautils \
- libmediametrics \
- libstagefright_foundation \
- libutils
-
-LOCAL_STATIC_LIBRARIES := \
- libregistermsext
-
-LOCAL_C_INCLUDES := \
- $(TOP)/frameworks/av/media/libstagefright/include \
- $(TOP)/frameworks/av/media/libstagefright/rtsp \
- $(TOP)/frameworks/av/media/libstagefright/wifi-display \
- $(TOP)/frameworks/av/media/libstagefright/webm \
- $(TOP)/frameworks/av/include/media \
- $(TOP)/frameworks/av/include/camera \
- $(TOP)/frameworks/native/include/media/openmax \
- $(TOP)/frameworks/native/include/media/hardware \
- $(TOP)/external/tremolo/Tremolo
-
-
-LOCAL_MODULE:= mediametrics
-
-LOCAL_INIT_RC := mediametrics.rc
-
-LOCAL_CFLAGS := -Werror -Wall -Wno-error=deprecated-declarations
-LOCAL_CLANG := true
-
-include $(BUILD_EXECUTABLE)
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index edf4dab..9bdd4c8 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -13,6 +13,9 @@
ppoll: 1
mmap2: 1
getrandom: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
# parser support for '<' is in this needs to be modified to also prevent
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index 6d88c84..a48cedb 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -55,6 +55,9 @@
nanosleep: 1
sched_setscheduler: 1
uname: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
# Required by AddressSanitizer
gettid: 1
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
index 588141a..02cedba 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
@@ -21,6 +21,9 @@
ppoll: 1
mprotect: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
mmap2: arg2 in ~PROT_EXEC || arg2 in ~PROT_WRITE
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
# parser support for '<' is in this needs to be modified to also prevent
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
index 1bee1b5..78ecaf5 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
@@ -26,6 +26,9 @@
fstat: 1
newfstatat: 1
fstatfs: 1
+memfd_create: 1
+ftruncate: 1
+ftruncate64: 1
# mremap: Ensure |flags| are (MREMAP_MAYMOVE | MREMAP_FIXED) TODO: Once minijail
# parser support for '<' is in this needs to be modified to also prevent
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
new file mode 100644
index 0000000..1c63f64
--- /dev/null
+++ b/services/mediaresourcemanager/Android.bp
@@ -0,0 +1,28 @@
+
+
+cc_library_shared {
+ name: "libresourcemanagerservice",
+
+ srcs: [
+ "ResourceManagerService.cpp",
+ "ServiceLog.cpp",
+ ],
+
+ shared_libs: [
+ "libmedia",
+ "libmediautils",
+ "libbinder",
+ "libutils",
+ "liblog",
+ ],
+
+ compile_multilib: "32",
+
+ include_dirs: ["frameworks/av/include"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+}
diff --git a/services/mediaresourcemanager/Android.mk b/services/mediaresourcemanager/Android.mk
deleted file mode 100644
index 5823036..0000000
--- a/services/mediaresourcemanager/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := ResourceManagerService.cpp ServiceLog.cpp
-
-LOCAL_SHARED_LIBRARIES := libmedia libmediautils libbinder libutils liblog
-
-LOCAL_MODULE:= libresourcemanagerservice
-
-LOCAL_32_BIT_ONLY := true
-
-LOCAL_C_INCLUDES += \
- frameworks/av/include
-
-LOCAL_CFLAGS += -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))