Merge "Replace AndroidRuntime::getJNIEnv() with stable methods"
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index 77dcd48..7c41b5e 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -479,6 +479,7 @@
case ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE:
case ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST:
case ACAMERA_CONTROL_ENABLE_ZSL:
+ case ACAMERA_CONTROL_BOKEH_MODE:
case ACAMERA_EDGE_MODE:
case ACAMERA_FLASH_MODE:
case ACAMERA_HOT_PIXEL_MODE:
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 68fe045..825f308 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -140,7 +140,7 @@
* application controls how the color mapping is performed.</p>
* <p>We define the expected processing pipeline below. For consistency
* across devices, this is always the case with TRANSFORM_MATRIX.</p>
- * <p>When either FULL or HIGH_QUALITY is used, the camera device may
+ * <p>When either FAST or HIGH_QUALITY is used, the camera device may
* do additional processing but ACAMERA_COLOR_CORRECTION_GAINS and
* ACAMERA_COLOR_CORRECTION_TRANSFORM will still be provided by the
* camera device (in the results) and be roughly correct.</p>
@@ -1734,6 +1734,77 @@
*/
ACAMERA_CONTROL_AF_SCENE_CHANGE = // byte (acamera_metadata_enum_android_control_af_scene_change_t)
ACAMERA_CONTROL_START + 42,
+ /**
+ * <p>The list of bokeh modes that are supported by this camera device, and each bokeh mode's
+ * maximum streaming (non-stall) size with bokeh effect.</p>
+ *
+ * <p>Type: int32[3*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>For OFF mode, the camera behaves normally with no bokeh effect.</p>
+ * <p>For STILL_CAPTURE mode, the maximum streaming dimension specifies the limit under which
+ * bokeh is effective when capture intent is PREVIEW. Note that when capture intent is
+ * PREVIEW, the bokeh effect may not be as high quality compared to STILL_CAPTURE intent
+ * in order to maintain reasonable frame rate. The maximum streaming dimension must be one
+ * of the YUV_420_888 or PRIVATE resolutions in availableStreamConfigurations, or (0, 0)
+ * if preview bokeh is not supported. If the application configures a stream larger than
+ * the maximum streaming dimension, bokeh effect may not be applied for this stream for
+ * PREVIEW intent.</p>
+ * <p>For CONTINUOUS mode, the maximum streaming dimension specifies the limit under which
+ * bokeh is effective. This dimension must be one of the YUV_420_888 or PRIVATE resolutions
+ * in availableStreamConfigurations, and if the sensor maximum resolution is larger than or
+ * equal to 1080p, the maximum streaming dimension must be at least 1080p. If the
+ * application configures a stream with larger dimension, the stream may not have bokeh
+ * effect applied.</p>
+ */
+ ACAMERA_CONTROL_AVAILABLE_BOKEH_CAPABILITIES = // int32[3*n]
+ ACAMERA_CONTROL_START + 43,
+ /**
+ * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+ *
+ * <p>Type: byte (acamera_metadata_enum_android_control_bokeh_mode_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+ * <li>ACaptureRequest</li>
+ * </ul></p>
+ *
+ * <p>With bokeh mode, the camera device may blur out the parts of scene that are not in
+ * focus, creating a bokeh (or shallow depth of field) effect for people or objects.</p>
+ * <p>When set to STILL_CAPTURE bokeh mode with STILL_CAPTURE capture intent, due to the extra
+ * processing needed for high quality bokeh effect, the stall may be longer than when
+ * capture intent is not STILL_CAPTURE.</p>
+ * <p>When set to STILL_CAPTURE bokeh mode with PREVIEW capture intent,</p>
+ * <ul>
+ * <li>If the camera device has BURST_CAPTURE capability, the frame rate requirement of
+ * BURST_CAPTURE must still be met.</li>
+ * <li>All streams not larger than the maximum streaming dimension for STILL_CAPTURE mode
+ * (queried via {@link ACAMERA_CONTROL_AVAILABLE_BOKEH_CAPABILITIES })
+ * will have preview bokeh effect applied.</li>
+ * </ul>
+ * <p>When set to CONTINUOUS mode, configured streams dimension should not exceed this mode's
+ * maximum streaming dimension in order to have bokeh effect applied. Bokeh effect may not
+ * be available for streams larger than the maximum streaming dimension.</p>
+ * <p>Switching between different bokeh modes may involve reconfiguration of the camera
+ * pipeline, resulting in long latency. The application should check this key against the
+ * available session keys queried via
+ * {@link ACameraManager_getCameraCharacteristics }.</p>
+ * <p>When bokeh mode is on, the camera device may override certain control parameters, such as
+ * reduce frame rate or use face priority scene mode, to achieve best power and quality
+ * tradeoffs. When turned on, AE, AWB, and AF run in auto modes, and only the mandatory
+ * stream combinations of LIMITED hardware level are guaranteed.</p>
+ * <p>For a logical multi-camera, bokeh may be implemented by stereo vision from sub-cameras
+ * with different field of view. As a result, when bokeh mode is enabled, the camera device
+ * may override android.scaler.CropRegion, and the field of view will be smaller than when
+ * bokeh mode is off.</p>
+ */
+ ACAMERA_CONTROL_BOKEH_MODE = // byte (acamera_metadata_enum_android_control_bokeh_mode_t)
+ ACAMERA_CONTROL_START + 44,
ACAMERA_CONTROL_END,
/**
@@ -7002,6 +7073,31 @@
} acamera_metadata_enum_android_control_af_scene_change_t;
+// ACAMERA_CONTROL_BOKEH_MODE
+typedef enum acamera_metadata_enum_acamera_control_bokeh_mode {
+ /**
+ * <p>Bokeh mode is disabled.</p>
+ */
+ ACAMERA_CONTROL_BOKEH_MODE_OFF = 0,
+
+ /**
+ * <p>High quality bokeh mode is enabled for all non-raw streams (including YUV,
+ * JPEG, and IMPLEMENTATION_DEFINED) when capture intent is STILL_CAPTURE. Due to the
+ * extra image processing, this mode may introduce additional stall to non-raw streams.
+ * This mode should be used in high quality still capture use case.</p>
+ */
+ ACAMERA_CONTROL_BOKEH_MODE_STILL_CAPTURE = 1,
+
+ /**
+ * <p>Bokeh effect must not slow down capture rate relative to sensor raw output,
+ * and the effect is applied to all processed streams no larger than the maximum
+ * streaming dimension. This mode should be used if performance and power are a
+ * priority, such as video recording.</p>
+ */
+ ACAMERA_CONTROL_BOKEH_MODE_CONTINUOUS = 2,
+
+} acamera_metadata_enum_android_control_bokeh_mode_t;
+
// ACAMERA_EDGE_MODE
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 9ae87d8..e8cfece 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -304,7 +304,7 @@
seekTimeUs = -1;
if (shouldSeek) {
- seekTimeUs = (rand() * (float)durationUs) / RAND_MAX;
+ seekTimeUs = (rand() * (float)durationUs) / (float)RAND_MAX;
options.setSeekTo(seekTimeUs);
printf("seeking to %" PRId64 " us (%.2f secs)\n",
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 52c7438..b3fd7e9 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -24,6 +24,7 @@
"SharedLibrary.cpp",
"DrmHal.cpp",
"CryptoHal.cpp",
+ "DrmUtils.cpp",
],
local_include_dirs: [
@@ -58,6 +59,12 @@
"libhidlbase",
],
+ export_shared_lib_headers: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
+ ],
+
cflags: [
"-Werror",
"-Wall",
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 8a08a7b..40077f9 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -39,6 +39,8 @@
#include <mediadrm/DrmSessionClientInterface.h>
#include <mediadrm/DrmSessionManager.h>
+#include <vector>
+
using drm::V1_0::KeyedVector;
using drm::V1_0::KeyRequestType;
using drm::V1_0::KeyType;
@@ -496,10 +498,6 @@
mEventLock.unlock();
if (listener != NULL) {
- Parcel obj;
- writeByteArray(obj, sessionId);
- writeByteArray(obj, data);
-
Mutex::Autolock lock(mNotifyLock);
DrmPlugin::EventType eventType;
switch(hEventType) {
@@ -521,7 +519,7 @@
default:
return Void();
}
- listener->notify(eventType, 0, &obj);
+ listener->sendEvent(eventType, sessionId, data);
}
return Void();
}
@@ -534,12 +532,8 @@
mEventLock.unlock();
if (listener != NULL) {
- Parcel obj;
- writeByteArray(obj, sessionId);
- obj.writeInt64(expiryTimeInMS);
-
Mutex::Autolock lock(mNotifyLock);
- listener->notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
+ listener->sendExpirationUpdate(sessionId, expiryTimeInMS);
}
return Void();
}
@@ -556,21 +550,17 @@
}
Return<void> DrmHal::sendKeysChange_1_2(const hidl_vec<uint8_t>& sessionId,
- const hidl_vec<KeyStatus>& keyStatusList, bool hasNewUsableKey) {
+ const hidl_vec<KeyStatus>& hKeyStatusList, bool hasNewUsableKey) {
mEventLock.lock();
sp<IDrmClient> listener = mListener;
mEventLock.unlock();
if (listener != NULL) {
- Parcel obj;
- writeByteArray(obj, sessionId);
-
- size_t nKeys = keyStatusList.size();
- obj.writeInt32(nKeys);
+ std::vector<DrmKeyStatus> keyStatusList;
+ size_t nKeys = hKeyStatusList.size();
for (size_t i = 0; i < nKeys; ++i) {
- const KeyStatus &keyStatus = keyStatusList[i];
- writeByteArray(obj, keyStatus.keyId);
+ const KeyStatus &keyStatus = hKeyStatusList[i];
uint32_t type;
switch(keyStatus.type) {
case KeyStatusType::USABLE:
@@ -593,19 +583,18 @@
type = DrmPlugin::kKeyStatusType_InternalError;
break;
}
- obj.writeInt32(type);
+ keyStatusList.push_back({type, keyStatus.keyId});
mMetrics.mKeyStatusChangeCounter.Increment(keyStatus.type);
}
- obj.writeInt32(hasNewUsableKey);
Mutex::Autolock lock(mNotifyLock);
- listener->notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
+ listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
} else {
// There's no listener. But we still want to count the key change
// events.
- size_t nKeys = keyStatusList.size();
+ size_t nKeys = hKeyStatusList.size();
for (size_t i = 0; i < nKeys; i++) {
- mMetrics.mKeyStatusChangeCounter.Increment(keyStatusList[i].type);
+ mMetrics.mKeyStatusChangeCounter.Increment(hKeyStatusList[i].type);
}
}
@@ -620,10 +609,8 @@
mEventLock.unlock();
if (listener != NULL) {
- Parcel obj;
- writeByteArray(obj, sessionId);
Mutex::Autolock lock(mNotifyLock);
- listener->notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &obj);
+ listener->sendSessionLostState(sessionId);
}
return Void();
}
@@ -1585,16 +1572,6 @@
cleanup();
}
-void DrmHal::writeByteArray(Parcel &obj, hidl_vec<uint8_t> const &vec)
-{
- if (vec.size()) {
- obj.writeInt32(vec.size());
- obj.write(vec.data(), vec.size());
- } else {
- obj.writeInt32(0);
- }
-}
-
void DrmHal::reportFrameworkMetrics() const
{
std::unique_ptr<MediaAnalyticsItem> item(MediaAnalyticsItem::create("mediadrm"));
diff --git a/drm/libmediadrm/DrmSessionManager.cpp b/drm/libmediadrm/DrmSessionManager.cpp
index 0b91b85..165a4d6 100644
--- a/drm/libmediadrm/DrmSessionManager.cpp
+++ b/drm/libmediadrm/DrmSessionManager.cpp
@@ -25,6 +25,7 @@
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <media/MediaResource.h>
+#include <mediadrm/DrmUtils.h>
#include <mediadrm/DrmSessionManager.h>
#include <unistd.h>
#include <utils/String8.h>
@@ -62,7 +63,8 @@
}
static sp<IResourceManagerService> getResourceManagerService() {
- if (property_get_bool("persist.device_config.media_native.mediadrmserver", 1)) {
+ if (DrmUtils::UseDrmService()) {
+ // Create ResourceManagerService object in mediadrmserver process
return new android::media::ResourceManagerService();
}
sp<IServiceManager> sm = defaultServiceManager();
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
new file mode 100644
index 0000000..5cfd7c0
--- /dev/null
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "DrmUtils"
+
+#include <utils/String16.h>
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
+
+#include <mediadrm/CryptoHal.h>
+#include <mediadrm/DrmHal.h>
+#include <mediadrm/DrmUtils.h>
+#include <mediadrm/ICrypto.h>
+#include <mediadrm/IDrm.h>
+#include <mediadrm/IMediaDrmService.h>
+
+namespace android {
+namespace DrmUtils {
+
+namespace {
+template<typename Iface>
+sp<Iface> MakeObjectWithService(status_t *pstatus) {
+ status_t err = OK;
+ status_t &status = pstatus ? *pstatus : err;
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("media.drm"));
+
+ sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
+ if (service == NULL) {
+ status = UNKNOWN_ERROR;
+ return NULL;
+ }
+
+ auto obj = service->makeObject<Iface>();
+ if (obj == NULL) {
+ status = UNKNOWN_ERROR;
+ return NULL;
+ }
+
+ status = obj->initCheck();
+ if (status != OK && status != NO_INIT) {
+ return NULL;
+ }
+ return obj;
+}
+
+template<typename Iface, typename Hal>
+sp<Iface> MakeObject(status_t *pstatus) {
+ if (UseDrmService()) {
+ return MakeObjectWithService<Iface>(pstatus);
+ } else {
+ return new Hal();
+ }
+}
+} // namespace
+
+bool UseDrmService() {
+ return property_get_bool("mediadrm.use_mediadrmserver", true);
+}
+
+sp<IDrm> MakeDrm(status_t *pstatus) {
+ return MakeObject<IDrm, DrmHal>(pstatus);
+}
+
+sp<ICrypto> MakeCrypto(status_t *pstatus) {
+ return MakeObject<ICrypto, CryptoHal>(pstatus);
+}
+
+} // namespace DrmUtils
+} // namespace android
diff --git a/drm/libmediadrm/IDrmClient.cpp b/drm/libmediadrm/IDrmClient.cpp
index 357de9d..2e05093 100644
--- a/drm/libmediadrm/IDrmClient.cpp
+++ b/drm/libmediadrm/IDrmClient.cpp
@@ -17,39 +17,104 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "IDrmClient"
-#include <utils/Log.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
+#include <hidl/HidlSupport.h>
#include <media/IMediaPlayerClient.h>
+#include <mediadrm/DrmUtils.h>
#include <mediadrm/IDrmClient.h>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
namespace android {
enum {
- NOTIFY = IBinder::FIRST_CALL_TRANSACTION,
+ SEND_EVENT = IBinder::FIRST_CALL_TRANSACTION,
+ SEND_EXPIRATION_UPDATE,
+ SEND_KEYS_CHANGE,
+ SEND_SESSION_LOST_STATE,
};
+namespace {
+
+hardware::hidl_vec<uint8_t> ReadByteArray(const Parcel &obj, status_t *err)
+{
+ int32_t len = obj.readInt32();
+ hardware::hidl_vec<uint8_t> ret;
+ if (len < 0) {
+ ALOGE("Invalid array len");
+ *err = BAD_VALUE;
+ return ret;
+ }
+ ret.resize(static_cast<size_t>(len));
+ *err = obj.read(ret.data(), ret.size());
+ return ret;
+}
+
+}
+
class BpDrmClient: public BpInterface<IDrmClient>
{
+ template <typename F>
+ void notify(uint32_t code, F fillParcel) {
+ Parcel obj, reply;
+ obj.writeInterfaceToken(IDrmClient::getInterfaceDescriptor());
+ fillParcel(obj);
+ remote()->transact(code, obj, &reply, IBinder::FLAG_ONEWAY);
+ }
+
public:
explicit BpDrmClient(const sp<IBinder>& impl)
: BpInterface<IDrmClient>(impl)
{
}
- virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj)
+ virtual void sendEvent(
+ DrmPlugin::EventType eventType,
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const hardware::hidl_vec<uint8_t> &data)
{
- Parcel data, reply;
- data.writeInterfaceToken(IDrmClient::getInterfaceDescriptor());
- data.writeInt32((int)eventType);
- data.writeInt32(extra);
- if (obj && obj->dataSize() > 0) {
- data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
- }
- remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
+ auto fillParcel = [&] (Parcel &p) {
+ DrmUtils::WriteEventToParcel(p, eventType, sessionId, data);
+ };
+ notify(SEND_EVENT, fillParcel);
+ }
+
+ virtual void sendExpirationUpdate(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ int64_t expiryTimeInMS)
+ {
+ auto fillParcel = [&] (Parcel &p) {
+ DrmUtils::WriteExpirationUpdateToParcel(p, sessionId, expiryTimeInMS);
+ };
+ notify(SEND_EXPIRATION_UPDATE, fillParcel);
+ }
+
+ virtual void sendKeysChange(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const std::vector<DrmKeyStatus> &keyStatusList,
+ bool hasNewUsableKey)
+ {
+ auto fillParcel = [&] (Parcel &p) {
+ DrmUtils::WriteKeysChange(p, sessionId, keyStatusList, hasNewUsableKey);
+ };
+ notify(SEND_KEYS_CHANGE, fillParcel);
+ }
+
+ virtual void sendSessionLostState(
+ const hardware::hidl_vec<uint8_t> &sessionId)
+ {
+ auto fillParcel = [&] (Parcel &p) {
+ DrmUtils::WriteByteArray(p, sessionId);
+ };
+ notify(SEND_SESSION_LOST_STATE, fillParcel);
}
};
@@ -58,23 +123,58 @@
// ----------------------------------------------------------------------
status_t BnDrmClient::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+ uint32_t code, const Parcel& obj, Parcel* reply, uint32_t flags)
{
- switch (code) {
- case NOTIFY: {
- CHECK_INTERFACE(IDrmClient, data, reply);
- int eventType = data.readInt32();
- int extra = data.readInt32();
- Parcel obj;
- if (data.dataAvail() > 0) {
- obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
- }
+ CHECK_INTERFACE(IDrmClient, obj, reply);
+ status_t err = NO_ERROR;
+ hardware::hidl_vec<uint8_t> sessionId(ReadByteArray(obj, &err));
+ if (err != NO_ERROR) {
+ ALOGE("Failed to read session id, error=%d", err);
+ return err;
+ }
- notify((DrmPlugin::EventType)eventType, extra, &obj);
+ switch (code) {
+ case SEND_EVENT: {
+ hardware::hidl_vec<uint8_t> data(ReadByteArray(obj, &err));
+ int eventType = obj.readInt32();
+ if (err == NO_ERROR) {
+ sendEvent(static_cast<DrmPlugin::EventType>(eventType), sessionId, data);
+ }
+ return err;
+ } break;
+ case SEND_EXPIRATION_UPDATE: {
+ int64_t expiryTimeInMS = obj.readInt64();
+ sendExpirationUpdate(sessionId, expiryTimeInMS);
+ return NO_ERROR;
+ } break;
+ case SEND_KEYS_CHANGE: {
+ // ...
+ int32_t n = obj.readInt32();
+ if (n < 0) {
+ return BAD_VALUE;
+ }
+ std::vector<DrmKeyStatus> keyStatusList;
+ for (int32_t i = 0; i < n; ++i) {
+ hardware::hidl_vec<uint8_t> keyId(ReadByteArray(obj, &err));
+ if (err != NO_ERROR) {
+ return err;
+ }
+ int32_t type = obj.readInt32();
+ if (type < 0) {
+ return BAD_VALUE;
+ }
+ keyStatusList.push_back({static_cast<uint32_t>(type), keyId});
+ }
+ int32_t hasNewUsableKey = obj.readInt32();
+ sendKeysChange(sessionId, keyStatusList, hasNewUsableKey);
+ return NO_ERROR;
+ } break;
+ case SEND_SESSION_LOST_STATE: {
+ sendSessionLostState(sessionId);
return NO_ERROR;
} break;
default:
- return BBinder::onTransact(code, data, reply, flags);
+ return BBinder::onTransact(code, obj, reply, flags);
}
}
diff --git a/drm/libmediadrm/IMediaDrmService.cpp b/drm/libmediadrm/IMediaDrmService.cpp
index f320d0b..0b650f2 100644
--- a/drm/libmediadrm/IMediaDrmService.cpp
+++ b/drm/libmediadrm/IMediaDrmService.cpp
@@ -85,4 +85,14 @@
// ----------------------------------------------------------------------------
+template<>
+sp<IDrm> IMediaDrmService::makeObject<IDrm>() {
+ return makeDrm();
+}
+
+template<>
+sp<ICrypto> IMediaDrmService::makeObject<ICrypto>() {
+ return makeCrypto();
+}
+
} // namespace android
diff --git a/drm/libmediadrm/include/mediadrm/IDrmClient.h b/drm/libmediadrm/include/mediadrm/IDrmClient.h
index 3b2fc7c..f8f2b25 100644
--- a/drm/libmediadrm/include/mediadrm/IDrmClient.h
+++ b/drm/libmediadrm/include/mediadrm/IDrmClient.h
@@ -22,14 +22,41 @@
#include <binder/Parcel.h>
#include <media/drm/DrmAPI.h>
+#include <android/hardware/drm/1.2/types.h>
+#include <hidl/HidlSupport.h>
+
+#include <cstdint>
+#include <vector>
+
namespace android {
+struct DrmKeyStatus {
+ const uint32_t type;
+ const hardware::hidl_vec<uint8_t> keyId;
+};
+
class IDrmClient: public IInterface
{
public:
DECLARE_META_INTERFACE(DrmClient);
- virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) = 0;
+ virtual void sendEvent(
+ DrmPlugin::EventType eventType,
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const hardware::hidl_vec<uint8_t> &data) = 0;
+
+ virtual void sendExpirationUpdate(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ int64_t expiryTimeInMS) = 0;
+
+ virtual void sendKeysChange(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const std::vector<DrmKeyStatus> &keyStatusList,
+ bool hasNewUsableKey) = 0;
+
+ virtual void sendSessionLostState(
+ const hardware::hidl_vec<uint8_t> &sessionId) = 0;
+
};
// ----------------------------------------------------------------------------
diff --git a/drm/libmediadrm/include/mediadrm/IMediaDrmService.h b/drm/libmediadrm/include/mediadrm/IMediaDrmService.h
index 323fae5..7dcce94 100644
--- a/drm/libmediadrm/include/mediadrm/IMediaDrmService.h
+++ b/drm/libmediadrm/include/mediadrm/IMediaDrmService.h
@@ -33,8 +33,12 @@
public:
DECLARE_META_INTERFACE(MediaDrmService);
+
virtual sp<ICrypto> makeCrypto() = 0;
virtual sp<IDrm> makeDrm() = 0;
+
+ template<typename I> sp<I> makeObject();
+
};
// ----------------------------------------------------------------------------
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
new file mode 100644
index 0000000..a5bc09b
--- /dev/null
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ANDROID_DRMUTILS_H
+#define ANDROID_DRMUTILS_H
+
+#include <utils/Errors.h> // for status_t
+#include <utils/StrongPointer.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+struct ICrypto;
+struct IDrm;
+
+namespace DrmUtils {
+
+bool UseDrmService();
+
+sp<IDrm> MakeDrm(status_t *pstatus = nullptr);
+
+sp<ICrypto> MakeCrypto(status_t *pstatus = nullptr);
+
+template<typename BA>
+void WriteByteArray(Parcel &obj, const BA &vec) {
+ obj.writeInt32(vec.size());
+ if (vec.size()) {
+ obj.write(vec.data(), vec.size());
+ }
+}
+
+template<typename ET, typename BA>
+void WriteEventToParcel(
+ Parcel &obj,
+ ET eventType,
+ const BA &sessionId,
+ const BA &data) {
+ WriteByteArray(obj, sessionId);
+ WriteByteArray(obj, data);
+ obj.writeInt32(eventType);
+}
+
+template<typename BA>
+void WriteExpirationUpdateToParcel(
+ Parcel &obj,
+ const BA &sessionId,
+ int64_t expiryTimeInMS) {
+ WriteByteArray(obj, sessionId);
+ obj.writeInt64(expiryTimeInMS);
+}
+
+template<typename BA, typename KSL>
+void WriteKeysChange(
+ Parcel &obj,
+ const BA &sessionId,
+ const KSL &keyStatusList,
+ bool hasNewUsableKey) {
+ WriteByteArray(obj, sessionId);
+ obj.writeInt32(keyStatusList.size());
+ for (const auto &keyStatus : keyStatusList) {
+ WriteByteArray(obj, keyStatus.keyId);
+ obj.writeInt32(keyStatus.type);
+ }
+ obj.writeInt32(hasNewUsableKey);
+}
+
+} // namespace DrmUtils
+
+} // namespace android
+
+#endif // ANDROID_DRMUTILS_H
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 84ce172..1947656 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -38,7 +38,7 @@
static constexpr int64_t kLogDurationUs = 5000000; // 5 secs
static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
- static constexpr size_t kMinBufferCountForEviction = 40;
+ static constexpr size_t kMinBufferCountForEviction = 25;
}
// Buffer structure in bufferpool process
@@ -723,8 +723,8 @@
mStats.mTotalFetches, mStats.mTotalTransfers);
}
for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
- if (!clearCache && mStats.mSizeCached < kMinAllocBytesForEviction
- && mBuffers.size() < kMinBufferCountForEviction) {
+ if (!clearCache && (mStats.mSizeCached < kMinAllocBytesForEviction
+ || mBuffers.size() < kMinBufferCountForEviction)) {
break;
}
auto it = mBuffers.find(*freeIt);
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index be52a1d..4db94f5 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -155,9 +155,7 @@
mNumBytesPerInputFrame(0u),
mOutBufferSize(0u),
mSentCodecSpecificData(false),
- mInputTimeSet(false),
mInputSize(0),
- mNextFrameTimestampUs(0),
mSignalledError(false),
mOutIndex(0u),
mRemainderLen(0u) {
@@ -182,9 +180,9 @@
c2_status_t C2SoftAacEnc::onStop() {
mSentCodecSpecificData = false;
- mInputTimeSet = false;
mInputSize = 0u;
- mNextFrameTimestampUs = 0;
+ mNextFrameTimestampUs.reset();
+ mLastFrameEndTimestampUs.reset();
mSignalledError = false;
mRemainderLen = 0;
return C2_OK;
@@ -201,9 +199,9 @@
c2_status_t C2SoftAacEnc::onFlush_sm() {
mSentCodecSpecificData = false;
- mInputTimeSet = false;
mInputSize = 0u;
- mNextFrameTimestampUs = 0;
+ mNextFrameTimestampUs.reset();
+ mLastFrameEndTimestampUs.reset();
return C2_OK;
}
@@ -366,9 +364,19 @@
data = view.data();
capacity = view.capacity();
}
- if (!mInputTimeSet && capacity > 0) {
- mNextFrameTimestampUs = work->input.ordinal.timestamp;
- mInputTimeSet = true;
+ c2_cntr64_t inputTimestampUs = work->input.ordinal.timestamp;
+ if (inputTimestampUs < mLastFrameEndTimestampUs.value_or(inputTimestampUs)) {
+ ALOGW("Correcting overlapping timestamp: last frame ended at %lldus but "
+ "current frame is starting at %lldus. Using the last frame's end timestamp",
+ mLastFrameEndTimestampUs->peekll(), inputTimestampUs.peekll());
+ inputTimestampUs = *mLastFrameEndTimestampUs;
+ }
+ if (capacity > 0) {
+ if (!mNextFrameTimestampUs) {
+ mNextFrameTimestampUs = work->input.ordinal.timestamp;
+ }
+ mLastFrameEndTimestampUs = inputTimestampUs
+ + (capacity / sizeof(int16_t) * 1000000ll / channelCount / sampleRate);
}
size_t numFrames =
@@ -376,8 +384,7 @@
/ mNumBytesPerInputFrame;
ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu "
"mNumBytesPerInputFrame = %u inputTS = %lld remaining = %zu",
- capacity, mInputSize, numFrames,
- mNumBytesPerInputFrame, work->input.ordinal.timestamp.peekll(),
+ capacity, mInputSize, numFrames, mNumBytesPerInputFrame, inputTimestampUs.peekll(),
mRemainderLen);
std::shared_ptr<C2LinearBlock> block;
@@ -505,8 +512,10 @@
mInputSize = 0;
int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples
+ outargs.numInSamples;
- c2_cntr64_t currentFrameTimestampUs = mNextFrameTimestampUs;
- mNextFrameTimestampUs = work->input.ordinal.timestamp
+ ALOGV("consumed = %d, capacity = %zu, inSamples = %d, outSamples = %d",
+ consumed, capacity, inargs.numInSamples, outargs.numInSamples);
+ c2_cntr64_t currentFrameTimestampUs = *mNextFrameTimestampUs;
+ mNextFrameTimestampUs = inputTimestampUs
+ (consumed * 1000000ll / channelCount / sampleRate);
std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
#if 0
@@ -533,7 +542,7 @@
}
ALOGV("encoderErr = %d mInputSize = %zu "
"inargs.numInSamples = %d, mNextFrameTimestampUs = %lld",
- encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs.peekll());
+ encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs->peekll());
}
if (eos && inBufferSize[0] > 0) {
if (numFrames && !block) {
@@ -617,9 +626,9 @@
(void)pool;
mSentCodecSpecificData = false;
- mInputTimeSet = false;
mInputSize = 0u;
- mNextFrameTimestampUs = 0;
+ mNextFrameTimestampUs.reset();
+ mLastFrameEndTimestampUs.reset();
// TODO: we don't have any pending work at this time to drain.
return C2_OK;
diff --git a/media/codec2/components/aac/C2SoftAacEnc.h b/media/codec2/components/aac/C2SoftAacEnc.h
index 6ecfbdd..9a28280 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.h
+++ b/media/codec2/components/aac/C2SoftAacEnc.h
@@ -18,6 +18,7 @@
#define ANDROID_C2_SOFT_AAC_ENC_H_
#include <atomic>
+#include <optional>
#include <SimpleC2Component.h>
@@ -54,9 +55,9 @@
UINT mOutBufferSize;
bool mSentCodecSpecificData;
- bool mInputTimeSet;
size_t mInputSize;
- c2_cntr64_t mNextFrameTimestampUs;
+ std::optional<c2_cntr64_t> mNextFrameTimestampUs;
+ std::optional<c2_cntr64_t> mLastFrameEndTimestampUs;
bool mSignalledError;
std::atomic_uint64_t mOutIndex;
diff --git a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
index 18e6db2..15564d9 100644
--- a/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
+++ b/media/codec2/components/vorbis/C2SoftVorbisDec.cpp
@@ -66,7 +66,7 @@
addParameter(
DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
.withDefault(new C2StreamSampleRateInfo::output(0u, 48000))
- .withFields({C2F(mSampleRate, value).inRange(8000, 96000)})
+ .withFields({C2F(mSampleRate, value).inRange(8000, 192000)})
.withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
.build());
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index 62076f8..c7d73f4 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -594,12 +594,10 @@
}
}
- int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
-
if (inSize) {
uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
vpx_codec_err_t err = vpx_codec_decode(
- mCodecCtx, bitstream, inSize, &frameIndex, 0);
+ mCodecCtx, bitstream, inSize, &work->input.ordinal.frameIndex, 0);
if (err != VPX_CODEC_OK) {
ALOGE("on2 decoder failed to decode frame. err: %d", err);
mSignalledError = true;
@@ -609,7 +607,20 @@
}
}
- (void)outputBuffer(pool, work);
+ status_t err = outputBuffer(pool, work);
+ if (err == NOT_ENOUGH_DATA) {
+ if (inSize > 0) {
+ ALOGV("Maybe non-display frame at %lld.",
+ work->input.ordinal.frameIndex.peekll());
+ // send the work back with empty buffer.
+ inSize = 0;
+ }
+ } else if (err != OK) {
+ ALOGD("Error while getting the output frame out");
+ // work->result would be already filled; do fillEmptyWork() below to
+ // send the work back.
+ inSize = 0;
+ }
if (eos) {
drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
@@ -743,16 +754,16 @@
}
return;
}
-bool C2SoftVpxDec::outputBuffer(
+status_t C2SoftVpxDec::outputBuffer(
const std::shared_ptr<C2BlockPool> &pool,
const std::unique_ptr<C2Work> &work)
{
- if (!(work && pool)) return false;
+ if (!(work && pool)) return BAD_VALUE;
vpx_codec_iter_t iter = nullptr;
vpx_image_t *img = vpx_codec_get_frame(mCodecCtx, &iter);
- if (!img) return false;
+ if (!img) return NOT_ENOUGH_DATA;
if (img->d_w != mWidth || img->d_h != mHeight) {
mWidth = img->d_w;
@@ -769,7 +780,7 @@
mSignalledError = true;
work->workletsProcessed = 1u;
work->result = C2_CORRUPTED;
- return false;
+ return UNKNOWN_ERROR;
}
}
@@ -792,18 +803,19 @@
if (err != C2_OK) {
ALOGE("fetchGraphicBlock for Output failed with status %d", err);
work->result = err;
- return false;
+ return UNKNOWN_ERROR;
}
C2GraphicView wView = block->map().get();
if (wView.error()) {
ALOGE("graphic view map failed %d", wView.error());
work->result = C2_CORRUPTED;
- return false;
+ return UNKNOWN_ERROR;
}
- ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d",
- block->width(), block->height(), mWidth, mHeight, (int)*(int64_t *)img->user_priv);
+ ALOGV("provided (%dx%d) required (%dx%d), out frameindex %lld",
+ block->width(), block->height(), mWidth, mHeight,
+ ((c2_cntr64_t *)img->user_priv)->peekll());
uint8_t *dst = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
size_t srcYStride = img->stride[VPX_PLANE_Y];
@@ -859,8 +871,8 @@
dstYStride, dstUVStride,
mWidth, mHeight);
}
- finishWork(*(int64_t *)img->user_priv, work, std::move(block));
- return true;
+ finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work, std::move(block));
+ return OK;
}
c2_status_t C2SoftVpxDec::drainInternal(
@@ -876,7 +888,7 @@
return C2_OMITTED;
}
- while ((outputBuffer(pool, work))) {
+ while (outputBuffer(pool, work) == OK) {
}
if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.h b/media/codec2/components/vpx/C2SoftVpxDec.h
index e51bcee..2065165 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.h
+++ b/media/codec2/components/vpx/C2SoftVpxDec.h
@@ -85,7 +85,7 @@
status_t destroyDecoder();
void finishWork(uint64_t index, const std::unique_ptr<C2Work> &work,
const std::shared_ptr<C2GraphicBlock> &block);
- bool outputBuffer(
+ status_t outputBuffer(
const std::shared_ptr<C2BlockPool> &pool,
const std::unique_ptr<C2Work> &work);
c2_status_t drainInternal(
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index 6dab70b..ebc7a8f 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -514,7 +514,7 @@
return;
}
vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, stride, vstride,
- mStrideAlign, (uint8_t*)rView->data()[0]);
+ mStrideAlign, mConversionBuffer.data());
vpx_img_set_rect(&raw_frame, 0, 0, width, height);
} else {
ALOGE("Conversion buffer is too small: %u x %u for %zu",
diff --git a/media/codec2/hidl/1.0/utils/Component.cpp b/media/codec2/hidl/1.0/utils/Component.cpp
index a9f20a4..8a84601 100644
--- a/media/codec2/hidl/1.0/utils/Component.cpp
+++ b/media/codec2/hidl/1.0/utils/Component.cpp
@@ -204,7 +204,8 @@
const sp<::android::hardware::media::bufferpool::V2_0::
IClientManager>& clientPoolManager)
: mComponent{component},
- mInterface{new ComponentInterface(component->intf(), store.get())},
+ mInterface{new ComponentInterface(component->intf(),
+ store->getParameterCache())},
mListener{listener},
mStore{store},
mBufferPoolSender{clientPoolManager} {
diff --git a/media/codec2/hidl/1.0/utils/ComponentInterface.cpp b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
index 39e5357..12078e0 100644
--- a/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentInterface.cpp
@@ -87,10 +87,10 @@
// ComponentInterface
ComponentInterface::ComponentInterface(
const std::shared_ptr<C2ComponentInterface>& intf,
- ComponentStore* store)
+ const std::shared_ptr<ParameterCache>& cache)
: mInterface{intf},
mConfigurable{new CachedConfigurable(std::make_unique<CompIntf>(intf))} {
- mInit = mConfigurable->init(store);
+ mInit = mConfigurable->init(cache);
}
c2_status_t ComponentInterface::status() const {
diff --git a/media/codec2/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
index 1e0a190..9b9d449 100644
--- a/media/codec2/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hidl/1.0/utils/ComponentStore.cpp
@@ -102,8 +102,29 @@
} // unnamed namespace
+struct ComponentStore::StoreParameterCache : public ParameterCache {
+ std::mutex mStoreMutex;
+ ComponentStore* mStore;
+
+ StoreParameterCache(ComponentStore* store): mStore{store} {
+ }
+
+ virtual c2_status_t validate(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>& params
+ ) override {
+ std::scoped_lock _lock(mStoreMutex);
+ return mStore ? mStore->validateSupportedParams(params) : C2_NO_INIT;
+ }
+
+ void onStoreDestroyed() {
+ std::scoped_lock _lock(mStoreMutex);
+ mStore = nullptr;
+ }
+};
+
ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
: mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+ mParameterCache{std::make_shared<StoreParameterCache>(this)},
mStore{store} {
std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
@@ -113,7 +134,12 @@
mParamReflector = mStore->getParamReflector();
// Retrieve supported parameters from store
- mInit = mConfigurable->init(this);
+ using namespace std::placeholders;
+ mInit = mConfigurable->init(mParameterCache);
+}
+
+ComponentStore::~ComponentStore() {
+ mParameterCache->onStoreDestroyed();
}
c2_status_t ComponentStore::status() const {
@@ -146,6 +172,10 @@
return res;
}
+std::shared_ptr<ParameterCache> ComponentStore::getParameterCache() const {
+ return mParameterCache;
+}
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
Return<void> ComponentStore::createComponent(
const hidl_string& name,
@@ -187,7 +217,7 @@
sp<IComponentInterface> interface;
if (res == C2_OK) {
onInterfaceLoaded(c2interface);
- interface = new ComponentInterface(c2interface, this);
+ interface = new ComponentInterface(c2interface, mParameterCache);
}
_hidl_cb(static_cast<Status>(res), interface);
return Void();
@@ -218,8 +248,9 @@
_hidl_cb(Status::CORRUPTED, nullptr);
return Void();
}
+ using namespace std::placeholders;
sp<InputSurface> inputSurface = new InputSurface(
- this,
+ mParameterCache,
std::make_shared<C2ReflectorHelper>(),
source->getHGraphicBufferProducer(),
source);
diff --git a/media/codec2/hidl/1.0/utils/Configurable.cpp b/media/codec2/hidl/1.0/utils/Configurable.cpp
index ec9c170..530576d 100644
--- a/media/codec2/hidl/1.0/utils/Configurable.cpp
+++ b/media/codec2/hidl/1.0/utils/Configurable.cpp
@@ -38,10 +38,11 @@
: mIntf{std::move(intf)} {
}
-c2_status_t CachedConfigurable::init(ComponentStore* store) {
+c2_status_t CachedConfigurable::init(
+ const std::shared_ptr<ParameterCache>& cache) {
// Retrieve supported parameters from store
c2_status_t init = mIntf->querySupportedParams(&mSupportedParams);
- c2_status_t validate = store->validateSupportedParams(mSupportedParams);
+ c2_status_t validate = cache->validate(mSupportedParams);
return init == C2_OK ? C2_OK : validate;
}
diff --git a/media/codec2/hidl/1.0/utils/InputSurface.cpp b/media/codec2/hidl/1.0/utils/InputSurface.cpp
index 2b4ca85..c3c32e9 100644
--- a/media/codec2/hidl/1.0/utils/InputSurface.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurface.cpp
@@ -137,9 +137,9 @@
}
std::shared_ptr<C2Component> comp = Component::findLocalComponent(sink);
if (comp) {
- connection = new InputSurfaceConnection(mSource, comp, mStore);
+ connection = new InputSurfaceConnection(mSource, comp, mParameterCache);
} else {
- connection = new InputSurfaceConnection(mSource, sink, mStore);
+ connection = new InputSurfaceConnection(mSource, sink, mParameterCache);
}
if (!connection->init()) {
connection = nullptr;
@@ -153,11 +153,11 @@
// Constructor is exclusive to ComponentStore.
InputSurface::InputSurface(
- const sp<ComponentStore>& store,
+ const std::shared_ptr<ParameterCache>& cache,
const std::shared_ptr<C2ReflectorHelper>& reflector,
const sp<HGraphicBufferProducer>& producer,
const sp<GraphicBufferSource>& source)
- : mStore{store},
+ : mParameterCache{cache},
mProducer{producer},
mSource{source},
mIntf{std::make_shared<Interface>(reflector)},
@@ -165,7 +165,7 @@
std::make_unique<ConfigurableIntf>(
mIntf, source))} {
- mConfigurable->init(store.get());
+ mConfigurable->init(mParameterCache);
}
} // namespace utils
diff --git a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
index c9932ef..5cc0d53 100644
--- a/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
+++ b/media/codec2/hidl/1.0/utils/InputSurfaceConnection.cpp
@@ -445,21 +445,21 @@
InputSurfaceConnection::InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
const std::shared_ptr<C2Component>& comp,
- const sp<ComponentStore>& store)
+ const std::shared_ptr<ParameterCache>& cache)
: mImpl{new Impl(source, comp)},
mConfigurable{new CachedConfigurable(
std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
- mConfigurable->init(store.get());
+ mConfigurable->init(cache);
}
InputSurfaceConnection::InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
const sp<IInputSink>& sink,
- const sp<ComponentStore>& store)
+ const std::shared_ptr<ParameterCache>& cache)
: mImpl{new Impl(source, sink)},
mConfigurable{new CachedConfigurable(
std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
- mConfigurable->init(store.get());
+ mConfigurable->init(cache);
}
Return<Status> InputSurfaceConnection::disconnect() {
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
index a5d235e..9102f92 100644
--- 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
@@ -45,7 +45,7 @@
struct ComponentInterface : public IComponentInterface {
ComponentInterface(
const std::shared_ptr<C2ComponentInterface>& interface,
- ComponentStore* store);
+ const std::shared_ptr<ParameterCache>& cache);
c2_status_t status() const;
virtual Return<sp<IConfigurable>> getConfigurable() override;
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 be80c62..fe7d048 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
@@ -54,7 +54,7 @@
struct ComponentStore : public IComponentStore {
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
- virtual ~ComponentStore() = default;
+ virtual ~ComponentStore();
/**
* Returns the status of the construction of this object.
@@ -68,6 +68,12 @@
c2_status_t validateSupportedParams(
const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
+ /**
+ * Returns the store's ParameterCache. This is used for validation by
+ * Configurable::init().
+ */
+ std::shared_ptr<ParameterCache> getParameterCache() const;
+
// Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
virtual Return<void> createComponent(
const hidl_string& name,
@@ -98,6 +104,8 @@
protected:
sp<CachedConfigurable> mConfigurable;
+ struct StoreParameterCache;
+ std::shared_ptr<StoreParameterCache> mParameterCache;
// Does bookkeeping for an interface that has been loaded.
void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
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 8095185..8f49a97 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
@@ -79,6 +79,20 @@
};
/**
+ * Type for validating and caching parameters when CachedConfigurable is
+ * initialized.
+ *
+ * This is meant to be created by the ComponentStore. The purpose of abstracting
+ * this is to allow different versions of ComponentStore to work with this
+ * CachedConfigurable.
+ */
+struct ParameterCache {
+ virtual c2_status_t validate(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>&) = 0;
+ virtual ~ParameterCache() = default;
+};
+
+/**
* Implementation of the IConfigurable interface that supports caching of
* supported parameters from a supplied ComponentStore.
*
@@ -91,7 +105,8 @@
struct CachedConfigurable : public IConfigurable {
CachedConfigurable(std::unique_ptr<ConfigurableC2Intf>&& intf);
- c2_status_t init(ComponentStore* store);
+ // Populates mSupportedParams.
+ c2_status_t init(const std::shared_ptr<ParameterCache> &cache);
// Methods from ::android::hardware::media::c2::V1_0::IConfigurable
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 29ed7ff..8f21cf8 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
@@ -62,14 +62,14 @@
class Interface;
class ConfigurableIntf;
- sp<ComponentStore> mStore;
+ std::shared_ptr<ParameterCache> mParameterCache;
sp<HGraphicBufferProducer> mProducer;
sp<GraphicBufferSource> mSource;
std::shared_ptr<Interface> mIntf;
sp<CachedConfigurable> mConfigurable;
InputSurface(
- const sp<ComponentStore>& store,
+ const std::shared_ptr<ParameterCache>& cache,
const std::shared_ptr<C2ReflectorHelper>& reflector,
const sp<HGraphicBufferProducer>& base,
const sp<GraphicBufferSource>& source);
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 758b6b2..475ce8b 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
@@ -62,12 +62,12 @@
InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
const std::shared_ptr<C2Component>& comp,
- const sp<ComponentStore>& store);
+ const std::shared_ptr<ParameterCache>& cache);
InputSurfaceConnection(
const sp<GraphicBufferSource>& source,
const sp<IInputSink>& sink,
- const sp<ComponentStore>& store);
+ const std::shared_ptr<ParameterCache>& cache);
bool init();
diff --git a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index a8a552c..6469735 100644
--- a/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -547,10 +547,6 @@
if (mCompName == raw) {
bitStreamInfo[0] = 8000;
bitStreamInfo[1] = 1;
- } else if (mCompName == g711alaw || mCompName == g711mlaw) {
- // g711 test data is all 1-channel and has no embedded config info.
- bitStreamInfo[0] = 8000;
- bitStreamInfo[1] = 1;
} else {
ASSERT_NO_FATAL_FAILURE(
getInputChannelInfo(mComponent, mCompName, bitStreamInfo));
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 8fffa5e..cd179be 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -1232,6 +1232,7 @@
} else {
BufferDescriptorInfo4 info = {
{
+ "C2GrallocAllocation",
width,
height,
1u, // layerCount
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 81e1b8c..6f85960 100755
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -1082,9 +1082,14 @@
const uint8_t *ptr = (const uint8_t *)data;
const uint8_t profile = ptr[2] >> 1;
const uint8_t bl_compatibility_id = (ptr[4]) >> 4;
+ bool create_two_tracks = false;
+
+ if (bl_compatibility_id && bl_compatibility_id != 15) {
+ create_two_tracks = true;
+ }
if (4 == profile || 7 == profile ||
- (profile >= 8 && profile < 11 && bl_compatibility_id)) {
+ (profile >= 8 && profile < 11 && create_two_tracks)) {
// we need a backward compatible track
ALOGV("Adding new backward compatible track");
Track *track_b = new Track;
@@ -2388,6 +2393,9 @@
}
case FOURCC("dvcC"):
case FOURCC("dvvC"): {
+
+ CHECK_EQ(chunk_data_size, 24);
+
auto buffer = heapbuffer<uint8_t>(chunk_data_size);
if (buffer.get() == NULL) {
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index ad79e9c..d1812e6 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -21,6 +21,7 @@
"AudioVolumeGroup.cpp",
],
shared_libs: [
+ "libaudiofoundation",
"libaudioutils",
"libbinder",
"libcutils",
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index 3cdf095..06fc23c 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -22,22 +22,6 @@
namespace android {
//
-// AudioDeviceTypeAddr implementation
-//
-status_t AudioDeviceTypeAddr::readFromParcel(Parcel *parcel) {
- mType = (audio_devices_t) parcel->readInt32();
- mAddress = parcel->readString8();
- return NO_ERROR;
-}
-
-status_t AudioDeviceTypeAddr::writeToParcel(Parcel *parcel) const {
- parcel->writeInt32((int32_t) mType);
- parcel->writeString8(mAddress);
- return NO_ERROR;
-}
-
-
-//
// AudioMixMatchCriterion implementation
//
AudioMixMatchCriterion::AudioMixMatchCriterion(audio_usage_t usage,
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 02dc516..20ca35c 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1519,6 +1519,13 @@
return aps->setRttEnabled(enabled);
}
+bool AudioSystem::isCallScreenModeSupported()
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return false;
+ return aps->isCallScreenModeSupported();
+}
+
// ---------------------------------------------------------------------------
int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 7cc95e5..f27e21a 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -104,7 +104,8 @@
GET_VOLUME_GROUP_FOR_ATTRIBUTES,
SET_ALLOWED_CAPTURE_POLICY,
MOVE_EFFECTS_TO_IO,
- SET_RTT_ENABLED
+ SET_RTT_ENABLED,
+ IS_CALL_SCREEN_MODE_SUPPORTED
};
#define MAX_ITEMS_PER_LIST 1024
@@ -1284,6 +1285,17 @@
}
return static_cast<status_t>(reply.readInt32());
}
+
+ virtual bool isCallScreenModeSupported()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ status_t status = remote()->transact(IS_CALL_SCREEN_MODE_SUPPORTED, data, &reply);
+ if (status != NO_ERROR) {
+ return false;
+ }
+ return reply.readBool();
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1346,7 +1358,8 @@
case GET_OFFLOAD_FORMATS_A2DP:
case LIST_AUDIO_VOLUME_GROUPS:
case GET_VOLUME_GROUP_FOR_ATTRIBUTES:
- case SET_RTT_ENABLED: {
+ case SET_RTT_ENABLED:
+ case IS_CALL_SCREEN_MODE_SUPPORTED: {
if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
@@ -2237,7 +2250,6 @@
reply->writeBool(isSupported);
return NO_ERROR;
}
-
case SET_UID_DEVICE_AFFINITY: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
const uid_t uid = (uid_t) data.readInt32();
@@ -2369,6 +2381,13 @@
return NO_ERROR;
}
+ case IS_CALL_SCREEN_MODE_SUPPORTED: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ bool isAvailable = isCallScreenModeSupported();
+ reply->writeBool(isAvailable);
+ return NO_ERROR;
+ }
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index ef39fd1..0ab1c9d 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -18,9 +18,10 @@
#ifndef ANDROID_AUDIO_POLICY_H
#define ANDROID_AUDIO_POLICY_H
+#include <binder/Parcel.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <system/audio.h>
#include <system/audio_policy.h>
-#include <binder/Parcel.h>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -60,19 +61,6 @@
#define MAX_MIXES_PER_POLICY 10
#define MAX_CRITERIA_PER_MIX 20
-class AudioDeviceTypeAddr {
-public:
- AudioDeviceTypeAddr() {}
- AudioDeviceTypeAddr(audio_devices_t type, String8 address) :
- mType(type), mAddress(address) {}
-
- status_t readFromParcel(Parcel *parcel);
- status_t writeToParcel(Parcel *parcel) const;
-
- audio_devices_t mType;
- String8 mAddress;
-};
-
class AudioMixMatchCriterion {
public:
AudioMixMatchCriterion() {}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 09e80b2..12da0de 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -19,6 +19,7 @@
#include <sys/types.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioPolicy.h>
#include <media/AudioProductStrategy.h>
#include <media/AudioVolumeGroup.h>
@@ -396,6 +397,8 @@
static status_t setRttEnabled(bool enabled);
+ static bool isCallScreenModeSupported();
+
// ----------------------------------------------------------------------------
class AudioVolumeGroupCallback : public RefBase
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index 32275cf..14c1d40 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -23,6 +23,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
#include <binder/IInterface.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
#include <media/IAudioPolicyServiceClient.h>
@@ -222,6 +223,8 @@
volume_group_t &volumeGroup) = 0;
virtual status_t setRttEnabled(bool enabled) = 0;
+
+ virtual bool isCallScreenModeSupported() = 0;
};
diff --git a/media/libaudiofoundation/Android.bp b/media/libaudiofoundation/Android.bp
index edc06d2..93bc4d9 100644
--- a/media/libaudiofoundation/Android.bp
+++ b/media/libaudiofoundation/Android.bp
@@ -19,6 +19,7 @@
srcs: [
"AudioContainers.cpp",
+ "AudioDeviceTypeAddr.cpp",
"AudioGain.cpp",
"AudioPort.cpp",
"AudioProfile.cpp",
diff --git a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
new file mode 100644
index 0000000..3e43ead
--- /dev/null
+++ b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 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 <media/AudioDeviceTypeAddr.h>
+
+namespace android {
+
+const char* AudioDeviceTypeAddr::getAddress() const {
+ return mAddress.c_str();
+}
+
+bool AudioDeviceTypeAddr::equals(const AudioDeviceTypeAddr& other) const {
+ return mType == other.mType && mAddress == other.mAddress;
+}
+
+status_t AudioDeviceTypeAddr::readFromParcel(const Parcel *parcel) {
+ status_t status;
+ if ((status = parcel->readUint32(&mType)) != NO_ERROR) return status;
+ status = parcel->readUtf8FromUtf16(&mAddress);
+ return status;
+}
+
+status_t AudioDeviceTypeAddr::writeToParcel(Parcel *parcel) const {
+ status_t status;
+ if ((status = parcel->writeUint32(mType)) != NO_ERROR) return status;
+ status = parcel->writeUtf8AsUtf16(mAddress);
+ return status;
+}
+
+}
\ No newline at end of file
diff --git a/media/libaudiofoundation/DeviceDescriptorBase.cpp b/media/libaudiofoundation/DeviceDescriptorBase.cpp
index 18fd184..d99c2c0 100644
--- a/media/libaudiofoundation/DeviceDescriptorBase.cpp
+++ b/media/libaudiofoundation/DeviceDescriptorBase.cpp
@@ -25,13 +25,23 @@
namespace android {
DeviceDescriptorBase::DeviceDescriptorBase(audio_devices_t type) :
- AudioPort("", AUDIO_PORT_TYPE_DEVICE,
- audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
- AUDIO_PORT_ROLE_SOURCE),
- mDeviceType(type)
+ DeviceDescriptorBase(type, "")
{
- if (audio_is_remote_submix_device(type)) {
- mAddress = "0";
+}
+
+DeviceDescriptorBase::DeviceDescriptorBase(audio_devices_t type, const std::string& address) :
+ DeviceDescriptorBase(AudioDeviceTypeAddr(type, address))
+{
+}
+
+DeviceDescriptorBase::DeviceDescriptorBase(const AudioDeviceTypeAddr &deviceTypeAddr) :
+ AudioPort("", AUDIO_PORT_TYPE_DEVICE,
+ audio_is_output_device(deviceTypeAddr.mType) ? AUDIO_PORT_ROLE_SINK :
+ AUDIO_PORT_ROLE_SOURCE),
+ mDeviceTypeAddr(deviceTypeAddr)
+{
+ if (mDeviceTypeAddr.mAddress.empty() && audio_is_remote_submix_device(mDeviceTypeAddr.mType)) {
+ mDeviceTypeAddr.mAddress = "0";
}
}
@@ -55,22 +65,22 @@
AudioPortConfig::toAudioPortConfig(dstConfig, srcConfig);
- dstConfig->role = audio_is_output_device(mDeviceType) ?
+ dstConfig->role = audio_is_output_device(mDeviceTypeAddr.mType) ?
AUDIO_PORT_ROLE_SINK : AUDIO_PORT_ROLE_SOURCE;
dstConfig->type = AUDIO_PORT_TYPE_DEVICE;
- dstConfig->ext.device.type = mDeviceType;
+ dstConfig->ext.device.type = mDeviceTypeAddr.mType;
- (void)audio_utils_strlcpy_zerofill(dstConfig->ext.device.address, mAddress.c_str());
+ (void)audio_utils_strlcpy_zerofill(dstConfig->ext.device.address, mDeviceTypeAddr.getAddress());
}
void DeviceDescriptorBase::toAudioPort(struct audio_port *port) const
{
- ALOGV("DeviceDescriptorBase::toAudioPort() handle %d type %08x", mId, mDeviceType);
+ ALOGV("DeviceDescriptorBase::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
AudioPort::toAudioPort(port);
toAudioPortConfig(&port->active_config);
port->id = mId;
- port->ext.device.type = mDeviceType;
- (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mAddress.c_str());
+ port->ext.device.type = mDeviceTypeAddr.mType;
+ (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mDeviceTypeAddr.getAddress());
}
void DeviceDescriptorBase::dump(std::string *dst, int spaces, int index,
@@ -86,10 +96,11 @@
}
dst->append(base::StringPrintf("%*s- type: %-48s\n",
- spaces, "", ::android::toString(mDeviceType).c_str()));
+ spaces, "", ::android::toString(mDeviceTypeAddr.mType).c_str()));
- if (mAddress.size() != 0) {
- dst->append(base::StringPrintf("%*s- address: %-32s\n", spaces, "", mAddress.c_str()));
+ if (mDeviceTypeAddr.mAddress.size() != 0) {
+ dst->append(base::StringPrintf(
+ "%*s- address: %-32s\n", spaces, "", mDeviceTypeAddr.getAddress()));
}
AudioPort::dump(dst, spaces, verbose);
}
@@ -97,15 +108,15 @@
std::string DeviceDescriptorBase::toString() const
{
std::stringstream sstream;
- sstream << "type:0x" << std::hex << type() << ",@:" << mAddress;
+ sstream << "type:0x" << std::hex << type() << ",@:" << mDeviceTypeAddr.mAddress;
return sstream.str();
}
void DeviceDescriptorBase::log() const
{
- ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId, mDeviceType,
- ::android::toString(mDeviceType).c_str(),
- mAddress.c_str());
+ ALOGI("Device id:%d type:0x%08X:%s, addr:%s", mId, mDeviceTypeAddr.mType,
+ ::android::toString(mDeviceTypeAddr.mType).c_str(),
+ mDeviceTypeAddr.getAddress());
AudioPort::log(" ");
}
@@ -115,8 +126,7 @@
return other != nullptr &&
static_cast<const AudioPort*>(this)->equals(other) &&
static_cast<const AudioPortConfig*>(this)->equals(other) &&
- mAddress.compare(other->address()) == 0 &&
- mDeviceType == other->type();
+ mDeviceTypeAddr.equals(other->mDeviceTypeAddr);
}
status_t DeviceDescriptorBase::writeToParcel(Parcel *parcel) const
@@ -124,8 +134,7 @@
status_t status = NO_ERROR;
if ((status = AudioPort::writeToParcel(parcel)) != NO_ERROR) return status;
if ((status = AudioPortConfig::writeToParcel(parcel)) != NO_ERROR) return status;
- if ((status = parcel->writeUtf8AsUtf16(mAddress)) != NO_ERROR) return status;
- if ((status = parcel->writeUint32(mDeviceType)) != NO_ERROR) return status;
+ if ((status = parcel->writeParcelable(mDeviceTypeAddr)) != NO_ERROR) return status;
return status;
}
@@ -134,8 +143,7 @@
status_t status = NO_ERROR;
if ((status = AudioPort::readFromParcel(parcel)) != NO_ERROR) return status;
if ((status = AudioPortConfig::readFromParcel(parcel)) != NO_ERROR) return status;
- if ((status = parcel->readUtf8FromUtf16(&mAddress)) != NO_ERROR) return status;
- if ((status = parcel->readUint32(&mDeviceType)) != NO_ERROR) return status;
+ if ((status = parcel->readParcelable(&mDeviceTypeAddr)) != NO_ERROR) return status;
return status;
}
diff --git a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
new file mode 100644
index 0000000..392a355
--- /dev/null
+++ b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <binder/Parcelable.h>
+#include <binder/Parcel.h>
+#include <system/audio.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+struct AudioDeviceTypeAddr : public Parcelable {
+ AudioDeviceTypeAddr() = default;
+
+ AudioDeviceTypeAddr(audio_devices_t type, const std::string& address) :
+ mType(type), mAddress(address) {}
+
+ const char* getAddress() const;
+
+ bool equals(const AudioDeviceTypeAddr& other) const;
+
+ status_t readFromParcel(const Parcel *parcel) override;
+
+ status_t writeToParcel(Parcel *parcel) const override;
+
+ audio_devices_t mType = AUDIO_DEVICE_NONE;
+ std::string mAddress;
+};
+
+}
diff --git a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
index 6a34b4d..434533e 100644
--- a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
+++ b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
@@ -19,6 +19,7 @@
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <media/AudioPort.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <utils/Errors.h>
#include <cutils/config_utils.h>
#include <system/audio.h>
@@ -31,12 +32,15 @@
public:
// Note that empty name refers by convention to a generic device.
explicit DeviceDescriptorBase(audio_devices_t type);
+ DeviceDescriptorBase(audio_devices_t type, const std::string& address);
+ explicit DeviceDescriptorBase(const AudioDeviceTypeAddr& deviceTypeAddr);
virtual ~DeviceDescriptorBase() {}
- audio_devices_t type() const { return mDeviceType; }
- std::string address() const { return mAddress; }
- void setAddress(const std::string &address) { mAddress = address; }
+ audio_devices_t type() const { return mDeviceTypeAddr.mType; }
+ std::string address() const { return mDeviceTypeAddr.mAddress; }
+ void setAddress(const std::string &address) { mDeviceTypeAddr.mAddress = address; }
+ const AudioDeviceTypeAddr& getDeviceTypeAddr() const { return mDeviceTypeAddr; }
// AudioPortConfig
virtual sp<AudioPort> getAudioPort() const {
@@ -59,8 +63,7 @@
status_t readFromParcel(const Parcel* parcel) override;
protected:
- std::string mAddress{""};
- audio_devices_t mDeviceType;
+ AudioDeviceTypeAddr mDeviceTypeAddr;
};
} // namespace android
diff --git a/media/libmediahelper/TypeConverter.cpp b/media/libmediahelper/TypeConverter.cpp
index 5be78d1..817aadf 100644
--- a/media/libmediahelper/TypeConverter.cpp
+++ b/media/libmediahelper/TypeConverter.cpp
@@ -325,6 +325,7 @@
MAKE_STRING_FROM_ENUM(AUDIO_MODE_RINGTONE),
MAKE_STRING_FROM_ENUM(AUDIO_MODE_IN_CALL),
MAKE_STRING_FROM_ENUM(AUDIO_MODE_IN_COMMUNICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_MODE_CALL_SCREEN),
TERMINATOR
};
diff --git a/media/libmediametrics/IMediaAnalyticsService.cpp b/media/libmediametrics/IMediaAnalyticsService.cpp
index 1ab6653..4324f6d 100644
--- a/media/libmediametrics/IMediaAnalyticsService.cpp
+++ b/media/libmediametrics/IMediaAnalyticsService.cpp
@@ -55,13 +55,17 @@
Parcel data;
data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
- item->writeToParcel(&data);
- status_t err = remote()->transact(
+ status_t status = item->writeToParcel(&data);
+ if (status != NO_ERROR) { // assume failure logged in item
+ return status;
+ }
+
+ status = remote()->transact(
SUBMIT_ITEM_ONEWAY, data, nullptr /* reply */, IBinder::FLAG_ONEWAY);
- ALOGW_IF(err != NO_ERROR, "%s: bad response from service for submit, err=%d",
- __func__, err);
- return err;
+ ALOGW_IF(status != NO_ERROR, "%s: bad response from service for submit, status=%d",
+ __func__, status);
+ return status;
}
};
@@ -79,11 +83,14 @@
CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
MediaAnalyticsItem * const item = MediaAnalyticsItem::create();
- if (item->readFromParcel(data) < 0) {
- return BAD_VALUE;
+ status_t status = item->readFromParcel(data);
+ if (status != NO_ERROR) { // assume failure logged in item
+ return status;
}
+ // TODO: remove this setPid.
item->setPid(clientPid);
- const status_t status __unused = submitInternal(item, true /* release */);
+ status = submitInternal(item, true /* release */);
+ // assume failure logged by submitInternal
return NO_ERROR;
} break;
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index a4efa49..14dce79 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#undef LOG_TAG
#define LOG_TAG "MediaAnalyticsItem"
#include <inttypes.h>
@@ -23,6 +22,7 @@
#include <sys/types.h>
#include <mutex>
+#include <set>
#include <binder/Parcel.h>
#include <utils/Errors.h>
@@ -45,18 +45,6 @@
// the service is off.
#define SVC_TRIES 2
-// So caller doesn't need to know size of allocated space
-MediaAnalyticsItem *MediaAnalyticsItem::create()
-{
- return MediaAnalyticsItem::create(kKeyNone);
-}
-
-MediaAnalyticsItem *MediaAnalyticsItem::create(MediaAnalyticsItem::Key key)
-{
- MediaAnalyticsItem *item = new MediaAnalyticsItem(key);
- return item;
-}
-
MediaAnalyticsItem* MediaAnalyticsItem::convert(mediametrics_handle_t handle) {
MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
return item;
@@ -159,64 +147,50 @@
return mPkgVersionCode;
}
-// this key is for the overall record -- "codec", "player", "drm", etc
-MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
- mKey = key;
- return *this;
-}
-
-// number of attributes we have in this record
-int32_t MediaAnalyticsItem::count() const {
- return mPropCount;
-}
// find the proper entry in the list
-size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len) const
+size_t MediaAnalyticsItem::findPropIndex(const char *name) const
{
size_t i = 0;
for (; i < mPropCount; i++) {
- if (mProps[i].isNamed(name, len)) break;
+ if (mProps[i].isNamed(name)) break;
}
return i;
}
MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) const {
- size_t len = strlen(name);
- size_t i = findPropIndex(name, len);
+ const size_t i = findPropIndex(name);
if (i < mPropCount) {
return &mProps[i];
}
- return NULL;
+ return nullptr;
}
// consider this "find-or-allocate".
// caller validates type and uses clearPropValue() accordingly
MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
- size_t len = strlen(name);
- size_t i = findPropIndex(name, len);
- Prop *prop;
-
+ const size_t i = findPropIndex(name);
if (i < mPropCount) {
- prop = &mProps[i];
- } else {
- if (i == mPropSize) {
- if (growProps() == false) {
- ALOGE("failed allocation for new props");
- return NULL;
- }
- }
- i = mPropCount++;
- prop = &mProps[i];
- prop->setName(name, len);
+ return &mProps[i]; // already have it, return
}
+ Prop *prop = allocateProp(); // get a new prop
+ if (prop == nullptr) return nullptr;
+ prop->setName(name);
return prop;
}
+MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp() {
+ if (mPropCount == mPropSize && growProps() == false) {
+ ALOGE("%s: failed allocation for new properties", __func__);
+ return nullptr;
+ }
+ return &mProps[mPropCount++];
+}
+
// used within the summarizers; return whether property existed
bool MediaAnalyticsItem::removeProp(const char *name) {
- size_t len = strlen(name);
- size_t i = findPropIndex(name, len);
+ const size_t i = findPropIndex(name);
if (i < mPropCount) {
mProps[i].clear();
if (i != mPropCount-1) {
@@ -231,19 +205,15 @@
// remove indicated keys and their values
// return value is # keys removed
-int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
- int zapped = 0;
- if (attrs == NULL || n <= 0) {
- return -1;
- }
- for (ssize_t i = 0 ; i < n ; i++) {
+size_t MediaAnalyticsItem::filter(size_t n, const char *attrs[]) {
+ size_t zapped = 0;
+ for (size_t i = 0; i < n; ++i) {
const char *name = attrs[i];
- size_t len = strlen(name);
- size_t j = findPropIndex(name, len);
+ size_t j = findPropIndex(name);
if (j >= mPropCount) {
// not there
continue;
- } else if (j+1 == mPropCount) {
+ } else if (j + 1 == mPropCount) {
// last one, shorten
zapped++;
mProps[j].clear();
@@ -261,35 +231,31 @@
// remove any keys NOT in the provided list
// return value is # keys removed
-int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
- int zapped = 0;
- if (attrs == NULL || n <= 0) {
- return -1;
- }
- for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
- Prop *prop = &mProps[i];
- for (ssize_t j = 0; j < n ; j++) {
- if (prop->isNamed(attrs[j])) {
- prop->clear();
- zapped++;
- if (i != (ssize_t)(mPropCount-1)) {
- *prop = mProps[mPropCount-1];
- }
- mProps[mPropCount-1].clear();
- mPropCount--;
- break;
- }
+size_t MediaAnalyticsItem::filterNot(size_t n, const char *attrs[]) {
+ std::set<std::string> check(attrs, attrs + n);
+ size_t zapped = 0;
+ for (size_t j = 0; j < mPropCount;) {
+ if (check.find(mProps[j].getName()) != check.end()) {
+ ++j;
+ continue;
+ }
+ if (j + 1 == mPropCount) {
+ // last one, shorten
+ zapped++;
+ mProps[j].clear();
+ mPropCount--;
+ break;
+ } else {
+ // in the middle, bring last one down and shorten
+ zapped++;
+ mProps[j].clear();
+ mProps[j] = mProps[mPropCount-1];
+ mPropCount--;
}
}
return zapped;
}
-// remove a single key
-// return value is 0 (not found) or 1 (found and removed)
-int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
- return filter(1, &name);
-}
-
bool MediaAnalyticsItem::growProps(int increment)
{
if (increment <= 0) {
@@ -314,98 +280,77 @@
// Parcel / serialize things for binder calls
//
-int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
- int32_t version = data.readInt32();
+status_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
+ int32_t version;
+ status_t status = data.readInt32(&version);
+ if (status != NO_ERROR) return status;
- switch(version) {
- case 0:
- return readFromParcel0(data);
- break;
- default:
- ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
- return -1;
+ switch (version) {
+ case 0:
+ return readFromParcel0(data);
+ default:
+ ALOGE("%s: unsupported parcel version: %d", __func__, version);
+ return INVALID_OPERATION;
}
}
-int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
- // into 'this' object
- // .. we make a copy of the string to put away.
- mKey = data.readCString();
- mPid = data.readInt32();
- mUid = data.readInt32();
- mPkgName = data.readCString();
- mPkgVersionCode = data.readInt64();
- // We no longer pay attention to user setting of finalized, BUT it's
- // still part of the wire packet -- so read & discard.
- mTimestamp = data.readInt64();
-
- int count = data.readInt32();
+status_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
+ const char *s = data.readCString();
+ mKey = s == nullptr ? "" : s;
+ int32_t pid, uid;
+ status_t status = data.readInt32(&pid) ?: data.readInt32(&uid);
+ if (status != NO_ERROR) return status;
+ mPid = (pid_t)pid;
+ mUid = (uid_t)uid;
+ s = data.readCString();
+ mPkgName = s == nullptr ? "" : s;
+ int32_t count;
+ int64_t version, timestamp;
+ status = data.readInt64(&version) ?: data.readInt64(×tamp) ?: data.readInt32(&count);
+ if (status != NO_ERROR) return status;
+ if (count < 0) return BAD_VALUE;
+ mPkgVersionCode = version;
+ mTimestamp = timestamp;
for (int i = 0; i < count ; i++) {
- MediaAnalyticsItem::Attr attr = data.readCString();
- int32_t ztype = data.readInt32();
- switch (ztype) {
- case MediaAnalyticsItem::kTypeInt32:
- setInt32(attr, data.readInt32());
- break;
- case MediaAnalyticsItem::kTypeInt64:
- setInt64(attr, data.readInt64());
- break;
- case MediaAnalyticsItem::kTypeDouble:
- setDouble(attr, data.readDouble());
- break;
- case MediaAnalyticsItem::kTypeCString:
- setCString(attr, data.readCString());
- break;
- case MediaAnalyticsItem::kTypeRate:
- {
- int64_t count = data.readInt64();
- int64_t duration = data.readInt64();
- setRate(attr, count, duration);
- }
- break;
- default:
- ALOGE("reading bad item type: %d, idx %d",
- ztype, i);
- return -1;
- }
+ Prop *prop = allocateProp();
+ status_t status = prop->readFromParcel(data);
+ if (status != NO_ERROR) return status;
}
-
- return 0;
+ return NO_ERROR;
}
-int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
+status_t MediaAnalyticsItem::writeToParcel(Parcel *data) const {
+ if (data == nullptr) return BAD_VALUE;
- if (data == NULL) return -1;
+ const int32_t version = 0;
+ status_t status = data->writeInt32(version);
+ if (status != NO_ERROR) return status;
- int32_t version = 0;
- data->writeInt32(version);
-
- switch(version) {
- case 0:
- return writeToParcel0(data);
- break;
- default:
- ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
- return -1;
+ switch (version) {
+ case 0:
+ return writeToParcel0(data);
+ default:
+ ALOGE("%s: unsupported parcel version: %d", __func__, version);
+ return INVALID_OPERATION;
}
}
-int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
+status_t MediaAnalyticsItem::writeToParcel0(Parcel *data) const {
+ status_t status =
+ data->writeCString(mKey.c_str())
+ ?: data->writeInt32(mPid)
+ ?: data->writeInt32(mUid)
+ ?: data->writeCString(mPkgName.c_str())
+ ?: data->writeInt64(mPkgVersionCode)
+ ?: data->writeInt64(mTimestamp);
+ if (status != NO_ERROR) return status;
- data->writeCString(mKey.c_str());
- data->writeInt32(mPid);
- data->writeInt32(mUid);
- data->writeCString(mPkgName.c_str());
- data->writeInt64(mPkgVersionCode);
- data->writeInt64(mTimestamp);
-
- // set of items
- const size_t count = mPropCount;
- data->writeInt32(count);
- for (size_t i = 0 ; i < count; i++ ) {
- mProps[i].writeToParcel(data);
+ data->writeInt32((int32_t)mPropCount);
+ for (size_t i = 0 ; i < mPropCount; ++i) {
+ status = mProps[i].writeToParcel(data);
+ if (status != NO_ERROR) return status;
}
- return 0;
+ return NO_ERROR;
}
const char *MediaAnalyticsItem::toCString() {
@@ -506,7 +451,6 @@
}
}
-
//static
bool MediaAnalyticsItem::isEnabled() {
// completely skip logging from certain UIDs. We do this here
@@ -634,199 +578,282 @@
return true;
}
-// a byte array; contents are
-// overall length (uint32) including the length field itself
-// encoding version (uint32)
-// count of properties (uint32)
-// N copies of:
-// property name as length(int16), bytes
-// the bytes WILL include the null terminator of the name
-// type (uint8 -- 1 byte)
-// size of value field (int16 -- 2 bytes)
-// value (size based on type)
-// int32, int64, double -- little endian 4/8/8 bytes respectively
-// cstring -- N bytes of value [WITH terminator]
+namespace {
-enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
-
-bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
-
- char *build = NULL;
-
- if (pbuffer == NULL || plength == NULL)
- return false;
-
- // consistency for the caller, who owns whatever comes back in this pointer.
- *pbuffer = NULL;
-
- // first, let's calculate sizes
- int32_t goal = 0;
- int32_t version = 0;
-
- goal += sizeof(uint32_t); // overall length, including the length field
- goal += sizeof(uint32_t); // encoding version
- goal += sizeof(uint32_t); // # properties
-
- int32_t count = mPropCount;
- for (int i = 0 ; i < count; i++ ) {
- Prop *prop = &mProps[i];
- goal += sizeof(uint16_t); // name length
- goal += strlen(prop->mName) + 1; // string + null
- goal += sizeof(uint8_t); // type
- goal += sizeof(uint16_t); // size of value
- switch (prop->mType) {
- case MediaAnalyticsItem::kTypeInt32:
- goal += sizeof(uint32_t);
- break;
- case MediaAnalyticsItem::kTypeInt64:
- goal += sizeof(uint64_t);
- break;
- case MediaAnalyticsItem::kTypeDouble:
- goal += sizeof(double);
- break;
- case MediaAnalyticsItem::kTypeRate:
- goal += 2 * sizeof(uint64_t);
- break;
- case MediaAnalyticsItem::kTypeCString:
- // length + actual string + null
- goal += strlen(prop->u.CStringValue) + 1;
- break;
- default:
- ALOGE("found bad Prop type: %d, idx %d, name %s",
- prop->mType, i, prop->mName);
- return false;
- }
+template <typename T>
+status_t insert(const T& val, char **bufferpptr, char *bufferptrmax)
+{
+ const size_t size = sizeof(val);
+ if (*bufferpptr + size > bufferptrmax) {
+ ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+ return BAD_VALUE;
}
-
- // now that we have a size... let's allocate and fill
- build = (char *)malloc(goal);
- if (build == NULL)
- return false;
-
- memset(build, 0, goal);
-
- char *filling = build;
-
-#define _INSERT(val, size) \
- { memcpy(filling, &(val), (size)); filling += (size);}
-#define _INSERTSTRING(val, size) \
- { memcpy(filling, (val), (size)); filling += (size);}
-
- _INSERT(goal, sizeof(int32_t));
- _INSERT(version, sizeof(int32_t));
- _INSERT(count, sizeof(int32_t));
-
- for (int i = 0 ; i < count; i++ ) {
- Prop *prop = &mProps[i];
- int16_t attrNameLen = strlen(prop->mName) + 1;
- _INSERT(attrNameLen, sizeof(int16_t));
- _INSERTSTRING(prop->mName, attrNameLen); // termination included
- int8_t elemtype;
- int16_t elemsize;
- switch (prop->mType) {
- case MediaAnalyticsItem::kTypeInt32:
- {
- elemtype = kInt32;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = sizeof(int32_t);
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERT(prop->u.int32Value, sizeof(int32_t));
- break;
- }
- case MediaAnalyticsItem::kTypeInt64:
- {
- elemtype = kInt64;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = sizeof(int64_t);
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERT(prop->u.int64Value, sizeof(int64_t));
- break;
- }
- case MediaAnalyticsItem::kTypeDouble:
- {
- elemtype = kDouble;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = sizeof(double);
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERT(prop->u.doubleValue, sizeof(double));
- break;
- }
- case MediaAnalyticsItem::kTypeRate:
- {
- elemtype = kRate;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = 2 * sizeof(uint64_t);
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERT(prop->u.rate.count, sizeof(uint64_t));
- _INSERT(prop->u.rate.duration, sizeof(uint64_t));
- break;
- }
- case MediaAnalyticsItem::kTypeCString:
- {
- elemtype = kCString;
- _INSERT(elemtype, sizeof(int8_t));
- elemsize = strlen(prop->u.CStringValue) + 1;
- _INSERT(elemsize, sizeof(int16_t));
-
- _INSERTSTRING(prop->u.CStringValue, elemsize);
- break;
- }
- default:
- // error if can't encode; warning if can't decode
- ALOGE("found bad Prop type: %d, idx %d, name %s",
- prop->mType, i, prop->mName);
- goto badness;
- }
- }
-
- if (build + goal != filling) {
- ALOGE("problems populating; wrote=%d planned=%d",
- (int)(filling-build), goal);
- goto badness;
- }
-
- *pbuffer = build;
- *plength = goal;
-
- return true;
-
- badness:
- free(build);
- return false;
+ memcpy(*bufferpptr, &val, size);
+ *bufferpptr += size;
+ return NO_ERROR;
}
-void MediaAnalyticsItem::Prop::writeToParcel(Parcel *data) const
+template <>
+status_t insert(const char * const& val, char **bufferpptr, char *bufferptrmax)
{
- data->writeCString(mName);
- data->writeInt32(mType);
+ const size_t size = strlen(val) + 1;
+ if (size > UINT16_MAX || *bufferpptr + size > bufferptrmax) {
+ ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+ return BAD_VALUE;
+ }
+ memcpy(*bufferpptr, val, size);
+ *bufferpptr += size;
+ return NO_ERROR;
+}
+
+template <>
+ __unused
+status_t insert(char * const& val, char **bufferpptr, char *bufferptrmax)
+{
+ return insert((const char *)val, bufferpptr, bufferptrmax);
+}
+
+template <typename T>
+status_t extract(T *val, const char **bufferpptr, const char *bufferptrmax)
+{
+ const size_t size = sizeof(*val);
+ if (*bufferpptr + size > bufferptrmax) {
+ ALOGE("%s: buffer exceeded with size %zu", __func__, size);
+ return BAD_VALUE;
+ }
+ memcpy(val, *bufferpptr, size);
+ *bufferpptr += size;
+ return NO_ERROR;
+}
+
+template <>
+status_t extract(char **val, const char **bufferpptr, const char *bufferptrmax)
+{
+ const char *ptr = *bufferpptr;
+ while (*ptr != 0) {
+ if (ptr >= bufferptrmax) {
+ ALOGE("%s: buffer exceeded", __func__);
+ }
+ ++ptr;
+ }
+ const size_t size = (ptr - *bufferpptr) + 1;
+ *val = (char *)malloc(size);
+ memcpy(*val, *bufferpptr, size);
+ *bufferpptr += size;
+ return NO_ERROR;
+}
+
+} // namespace
+
+status_t MediaAnalyticsItem::writeToByteString(char **pbuffer, size_t *plength) const
+{
+ if (pbuffer == nullptr || plength == nullptr)
+ return BAD_VALUE;
+
+ // get size
+ const size_t keySizeZeroTerminated = strlen(mKey.c_str()) + 1;
+ if (keySizeZeroTerminated > UINT16_MAX) {
+ ALOGW("%s: key size %zu too large", __func__, keySizeZeroTerminated);
+ return INVALID_OPERATION;
+ }
+ const uint16_t version = 0;
+ const uint32_t header_len =
+ sizeof(uint32_t) // overall length
+ + sizeof(header_len) // header length
+ + sizeof(version) // encoding version
+ + sizeof(uint16_t) // key length
+ + keySizeZeroTerminated // key, zero terminated
+ + sizeof(int32_t) // pid
+ + sizeof(int32_t) // uid
+ + sizeof(int64_t) // timestamp
+ ;
+
+ uint32_t len = header_len
+ + sizeof(uint32_t) // # properties
+ ;
+ for (size_t i = 0 ; i < mPropCount; ++i) {
+ const size_t size = mProps[i].getByteStringSize();
+ if (size > UINT_MAX - 1) {
+ ALOGW("%s: prop %zu has size %zu", __func__, i, size);
+ return INVALID_OPERATION;
+ }
+ len += size;
+ }
+
+ // TODO: consider package information and timestamp.
+
+ // now that we have a size... let's allocate and fill
+ char *build = (char *)calloc(1 /* nmemb */, len);
+ if (build == nullptr) return NO_MEMORY;
+
+ char *filling = build;
+ char *buildmax = build + len;
+ if (insert(len, &filling, buildmax) != NO_ERROR
+ || insert(header_len, &filling, buildmax) != NO_ERROR
+ || insert(version, &filling, buildmax) != NO_ERROR
+ || insert((uint16_t)keySizeZeroTerminated, &filling, buildmax) != NO_ERROR
+ || insert(mKey.c_str(), &filling, buildmax) != NO_ERROR
+ || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR
+ || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR
+ || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR
+ || insert((uint32_t)mPropCount, &filling, buildmax) != NO_ERROR) {
+ ALOGD("%s:could not write header", __func__);
+ free(build);
+ return INVALID_OPERATION;
+ }
+ for (size_t i = 0 ; i < mPropCount; ++i) {
+ if (mProps[i].writeToByteString(&filling, buildmax) != NO_ERROR) {
+ free(build);
+ ALOGD("%s:could not write prop %zu of %zu", __func__, i, mPropCount);
+ return INVALID_OPERATION;
+ }
+ }
+
+ if (filling != buildmax) {
+ ALOGE("problems populating; wrote=%d planned=%d",
+ (int)(filling - build), len);
+ free(build);
+ return INVALID_OPERATION;
+ }
+ *pbuffer = build;
+ *plength = len;
+ return NO_ERROR;
+}
+
+status_t MediaAnalyticsItem::readFromByteString(const char *bufferptr, size_t length)
+{
+ if (bufferptr == nullptr) return BAD_VALUE;
+
+ const char *read = bufferptr;
+ const char *readend = bufferptr + length;
+
+ uint32_t len;
+ uint32_t header_len;
+ int16_t version;
+ int16_t key_len;
+ char *key = nullptr;
+ int32_t pid;
+ int32_t uid;
+ int64_t timestamp;
+ uint32_t propCount;
+ if (extract(&len, &read, readend) != NO_ERROR
+ || extract(&header_len, &read, readend) != NO_ERROR
+ || extract(&version, &read, readend) != NO_ERROR
+ || extract(&key_len, &read, readend) != NO_ERROR
+ || extract(&key, &read, readend) != NO_ERROR
+ || extract(&pid, &read, readend) != NO_ERROR
+ || extract(&uid, &read, readend) != NO_ERROR
+ || extract(×tamp, &read, readend) != NO_ERROR
+ || len > length
+ || header_len > len) {
+ free(key);
+ ALOGD("%s: invalid header", __func__);
+ return INVALID_OPERATION;
+ }
+ mKey = key;
+ free(key);
+ const size_t pos = read - bufferptr;
+ if (pos > header_len) {
+ ALOGD("%s: invalid header pos:%zu > header_len:%u",
+ __func__, pos, header_len);
+ return INVALID_OPERATION;
+ } else if (pos < header_len) {
+ ALOGD("%s: mismatched header pos:%zu < header_len:%u, advancing",
+ __func__, pos, header_len);
+ read += (header_len - pos);
+ }
+ if (extract(&propCount, &read, readend) != NO_ERROR) {
+ ALOGD("%s: cannot read prop count", __func__);
+ return INVALID_OPERATION;
+ }
+ mPid = pid;
+ mUid = uid;
+ mTimestamp = timestamp;
+ for (size_t i = 0; i < propCount; ++i) {
+ Prop *prop = allocateProp();
+ if (prop->readFromByteString(&read, readend) != NO_ERROR) {
+ ALOGD("%s: cannot read prop %zu", __func__, i);
+ return INVALID_OPERATION;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t MediaAnalyticsItem::Prop::writeToParcel(Parcel *data) const
+{
switch (mType) {
case kTypeInt32:
- data->writeInt32(u.int32Value);
- break;
+ return data->writeCString(mName)
+ ?: data->writeInt32(mType)
+ ?: data->writeInt32(u.int32Value);
case kTypeInt64:
- data->writeInt64(u.int64Value);
- break;
+ return data->writeCString(mName)
+ ?: data->writeInt32(mType)
+ ?: data->writeInt64(u.int64Value);
case kTypeDouble:
- data->writeDouble(u.doubleValue);
- break;
+ return data->writeCString(mName)
+ ?: data->writeInt32(mType)
+ ?: data->writeDouble(u.doubleValue);
case kTypeRate:
- data->writeInt64(u.rate.count);
- data->writeInt64(u.rate.duration);
- break;
+ return data->writeCString(mName)
+ ?: data->writeInt32(mType)
+ ?: data->writeInt64(u.rate.first)
+ ?: data->writeInt64(u.rate.second);
case kTypeCString:
- data->writeCString(u.CStringValue);
- break;
+ return data->writeCString(mName)
+ ?: data->writeInt32(mType)
+ ?: data->writeCString(u.CStringValue);
default:
ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName);
- break;
+ return BAD_VALUE;
}
}
-void MediaAnalyticsItem::Prop::toString(char *buffer, size_t length) const {
+status_t MediaAnalyticsItem::Prop::readFromParcel(const Parcel& data)
+{
+ const char *key = data.readCString();
+ if (key == nullptr) return BAD_VALUE;
+ int32_t type;
+ status_t status = data.readInt32(&type);
+ if (status != NO_ERROR) return status;
+ switch (type) {
+ case kTypeInt32:
+ status = data.readInt32(&u.int32Value);
+ break;
+ case kTypeInt64:
+ status = data.readInt64(&u.int64Value);
+ break;
+ case kTypeDouble:
+ status = data.readDouble(&u.doubleValue);
+ break;
+ case kTypeCString: {
+ const char *s = data.readCString();
+ if (s == nullptr) return BAD_VALUE;
+ set(s);
+ break;
+ }
+ case kTypeRate: {
+ std::pair<int64_t, int64_t> rate;
+ status = data.readInt64(&rate.first)
+ ?: data.readInt64(&rate.second);
+ if (status == NO_ERROR) {
+ set(rate);
+ }
+ break;
+ }
+ default:
+ ALOGE("%s: reading bad item type: %d", __func__, mType);
+ return BAD_VALUE;
+ }
+ if (status == NO_ERROR) {
+ setName(key);
+ mType = (Type)type;
+ }
+ return status;
+}
+
+void MediaAnalyticsItem::Prop::toString(char *buffer, size_t length) const
+{
switch (mType) {
case kTypeInt32:
snprintf(buffer, length, "%s=%d:", mName, u.int32Value);
@@ -839,7 +866,7 @@
break;
case MediaAnalyticsItem::kTypeRate:
snprintf(buffer, length, "%s=%lld/%lld:",
- mName, (long long)u.rate.count, (long long)u.rate.duration);
+ mName, (long long)u.rate.first, (long long)u.rate.second);
break;
case MediaAnalyticsItem::kTypeCString:
// TODO sanitize string for ':' '='
@@ -852,5 +879,168 @@
}
}
-} // namespace android
+size_t MediaAnalyticsItem::Prop::getByteStringSize() const
+{
+ const size_t header =
+ sizeof(uint16_t) // length
+ + sizeof(uint8_t) // type
+ + strlen(mName) + 1; // mName + 0 termination
+ size_t payload = 0;
+ switch (mType) {
+ case MediaAnalyticsItem::kTypeInt32:
+ payload = sizeof(u.int32Value);
+ break;
+ case MediaAnalyticsItem::kTypeInt64:
+ payload = sizeof(u.int64Value);
+ break;
+ case MediaAnalyticsItem::kTypeDouble:
+ payload = sizeof(u.doubleValue);
+ break;
+ case MediaAnalyticsItem::kTypeRate:
+ payload = sizeof(u.rate.first) + sizeof(u.rate.second);
+ break;
+ case MediaAnalyticsItem::kTypeCString:
+ payload = strlen(u.CStringValue) + 1;
+ break;
+ default:
+ ALOGE("%s: found bad prop type: %d, name %s",
+ __func__, mType, mName); // no payload computed
+ break;
+ }
+ return header + payload;
+}
+// TODO: fold into a template later.
+status_t MediaAnalyticsItem::writeToByteString(
+ const char *name, int32_t value, char **bufferpptr, char *bufferptrmax)
+{
+ const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
+ if (len > UINT16_MAX) return BAD_VALUE;
+ return insert((uint16_t)len, bufferpptr, bufferptrmax)
+ ?: insert((uint8_t)kTypeInt32, bufferpptr, bufferptrmax)
+ ?: insert(name, bufferpptr, bufferptrmax)
+ ?: insert(value, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+ const char *name, int64_t value, char **bufferpptr, char *bufferptrmax)
+{
+ const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
+ if (len > UINT16_MAX) return BAD_VALUE;
+ return insert((uint16_t)len, bufferpptr, bufferptrmax)
+ ?: insert((uint8_t)kTypeInt64, bufferpptr, bufferptrmax)
+ ?: insert(name, bufferpptr, bufferptrmax)
+ ?: insert(value, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+ const char *name, double value, char **bufferpptr, char *bufferptrmax)
+{
+ const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value);
+ if (len > UINT16_MAX) return BAD_VALUE;
+ return insert((uint16_t)len, bufferpptr, bufferptrmax)
+ ?: insert((uint8_t)kTypeDouble, bufferpptr, bufferptrmax)
+ ?: insert(name, bufferpptr, bufferptrmax)
+ ?: insert(value, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+ const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax)
+{
+ const size_t len = 2 + 1 + strlen(name) + 1 + 8 + 8;
+ if (len > UINT16_MAX) return BAD_VALUE;
+ return insert((uint16_t)len, bufferpptr, bufferptrmax)
+ ?: insert((uint8_t)kTypeRate, bufferpptr, bufferptrmax)
+ ?: insert(name, bufferpptr, bufferptrmax)
+ ?: insert(value.first, bufferpptr, bufferptrmax)
+ ?: insert(value.second, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+ const char *name, char * const &value, char **bufferpptr, char *bufferptrmax)
+{
+ const size_t len = 2 + 1 + strlen(name) + 1 + strlen(value) + 1;
+ if (len > UINT16_MAX) return BAD_VALUE;
+ return insert((uint16_t)len, bufferpptr, bufferptrmax)
+ ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
+ ?: insert(name, bufferpptr, bufferptrmax)
+ ?: insert(value, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::writeToByteString(
+ const char *name, const none_t &, char **bufferpptr, char *bufferptrmax)
+{
+ const size_t len = 2 + 1 + strlen(name) + 1;
+ if (len > UINT16_MAX) return BAD_VALUE;
+ return insert((uint16_t)len, bufferpptr, bufferptrmax)
+ ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax)
+ ?: insert(name, bufferpptr, bufferptrmax);
+}
+
+status_t MediaAnalyticsItem::Prop::writeToByteString(
+ char **bufferpptr, char *bufferptrmax) const
+{
+ switch (mType) {
+ case kTypeInt32:
+ return MediaAnalyticsItem::writeToByteString(mName, u.int32Value, bufferpptr, bufferptrmax);
+ case kTypeInt64:
+ return MediaAnalyticsItem::writeToByteString(mName, u.int64Value, bufferpptr, bufferptrmax);
+ case kTypeDouble:
+ return MediaAnalyticsItem::writeToByteString(mName, u.doubleValue, bufferpptr, bufferptrmax);
+ case kTypeRate:
+ return MediaAnalyticsItem::writeToByteString(mName, u.rate, bufferpptr, bufferptrmax);
+ case kTypeCString:
+ return MediaAnalyticsItem::writeToByteString(mName, u.CStringValue, bufferpptr, bufferptrmax);
+ case kTypeNone:
+ return MediaAnalyticsItem::writeToByteString(mName, none_t{}, bufferpptr, bufferptrmax);
+ default:
+ ALOGE("%s: found bad prop type: %d, name %s",
+ __func__, mType, mName); // no payload sent
+ return BAD_VALUE;
+ }
+}
+
+status_t MediaAnalyticsItem::Prop::readFromByteString(
+ const char **bufferpptr, const char *bufferptrmax)
+{
+ uint16_t len;
+ char *name;
+ uint8_t type;
+ status_t status = extract(&len, bufferpptr, bufferptrmax)
+ ?: extract(&type, bufferpptr, bufferptrmax)
+ ?: extract(&name, bufferpptr, bufferptrmax);
+ if (status != NO_ERROR) return status;
+ if (mName != nullptr) {
+ free(mName);
+ }
+ mName = name;
+ if (mType == kTypeCString) {
+ free(u.CStringValue);
+ u.CStringValue = nullptr;
+ }
+ mType = (Type)type;
+ switch (mType) {
+ case kTypeInt32:
+ return extract(&u.int32Value, bufferpptr, bufferptrmax);
+ case kTypeInt64:
+ return extract(&u.int64Value, bufferpptr, bufferptrmax);
+ case kTypeDouble:
+ return extract(&u.doubleValue, bufferpptr, bufferptrmax);
+ case kTypeRate:
+ return extract(&u.rate.first, bufferpptr, bufferptrmax)
+ ?: extract(&u.rate.second, bufferpptr, bufferptrmax);
+ case kTypeCString:
+ status = extract(&u.CStringValue, bufferpptr, bufferptrmax);
+ if (status != NO_ERROR) mType = kTypeNone;
+ return status;
+ case kTypeNone:
+ return NO_ERROR;
+ default:
+ mType = kTypeNone;
+ ALOGE("%s: found bad prop type: %d, name %s",
+ __func__, mType, mName); // no payload sent
+ return BAD_VALUE;
+ }
+}
+
+} // namespace android
diff --git a/media/libmediametrics/MediaMetrics.cpp b/media/libmediametrics/MediaMetrics.cpp
index 360ae0c..cf268e0 100644
--- a/media/libmediametrics/MediaMetrics.cpp
+++ b/media/libmediametrics/MediaMetrics.cpp
@@ -195,6 +195,6 @@
bool mediametrics_getAttributes(mediametrics_handle_t handle, char **buffer, size_t *length) {
android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
if (item == NULL) return false;
- return item->dumpAttributes(buffer, length);
+ return item->writeToByteString(buffer, length) == android::NO_ERROR;
}
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index f0deaaf..5558211 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -19,6 +19,7 @@
#include "MediaMetrics.h"
+#include <algorithm>
#include <string>
#include <sys/types.h>
@@ -34,8 +35,44 @@
class IMediaAnalyticsService;
class Parcel;
-// the class interface
-//
+/*
+ * Media Metrics
+ * Byte String format for communication of MediaAnalyticsItem.
+ *
+ * .... begin of item
+ * .... begin of header
+ * (uint32) length: including the length field itself
+ * (uint32) header length, including header_length and length fields.
+ * (uint16) version: 0
+ * (uint16) key length, including zero termination
+ * (int8)+ key string, including 0 termination
+ * (int32) pid
+ * (int32) uid
+ * (int64) timestamp
+ * .... end of header
+ * .... begin body
+ * (uint32) properties
+ * #properties of the following:
+ * (uint16) property_length, including property_length field itself
+ * (uint8) type of property
+ * (int8)+ key string, including 0 termination
+ * based on type of property (above), one of:
+ * (int32)
+ * (int64)
+ * (double)
+ * (int8)+ for cstring, including 0 termination
+ * (int64, int64) for rate
+ * .... end body
+ * .... end of item
+ */
+
+/**
+ * Media Metrics MediaAnalyticsItem
+ *
+ * A mutable item representing an event or record that will be
+ * logged with the Media Metrics service.
+ *
+ */
class MediaAnalyticsItem {
friend class MediaMetricsJNI; // TODO: remove this access
@@ -52,21 +89,9 @@
kTypeRate = 5,
};
- // Key: the record descriminator
- // values for the record discriminator
- // values can be "component/component"
- // basic values: "video", "audio", "drm"
- // XXX: need to better define the format
- using Key = std::string;
static constexpr const char * const kKeyNone = "none";
static constexpr const char * const kKeyAny = "any";
- // Attr: names for attributes within a record
- // format "prop1" or "prop/subprop"
- // XXX: need to better define the format
- typedef const char *Attr;
-
-
enum {
PROTO_V0 = 0,
PROTO_FIRST = PROTO_V0,
@@ -78,11 +103,36 @@
template <typename T>
explicit MediaAnalyticsItem(T key)
: mKey(key) { }
+ MediaAnalyticsItem() = default;
+
MediaAnalyticsItem(const MediaAnalyticsItem&) = delete;
MediaAnalyticsItem &operator=(const MediaAnalyticsItem&) = delete;
- static MediaAnalyticsItem* create(Key key);
- static MediaAnalyticsItem* create();
+ bool operator==(const MediaAnalyticsItem& other) const {
+ if (mPropCount != other.mPropCount
+ || mPid != other.mPid
+ || mUid != other.mUid
+ || mPkgName != other.mPkgName
+ || mPkgVersionCode != other.mPkgVersionCode
+ || mKey != other.mKey
+ || mTimestamp != other.mTimestamp) return false;
+ for (size_t i = 0; i < mPropCount; ++i) {
+ Prop *p = other.findProp(mProps[i].getName());
+ if (p == nullptr || mProps[i] != *p) return false;
+ }
+ return true;
+ }
+ bool operator!=(const MediaAnalyticsItem& other) const {
+ return !(*this == other);
+ }
+
+ template <typename T>
+ static MediaAnalyticsItem* create(T key) {
+ return new MediaAnalyticsItem(key);
+ }
+ static MediaAnalyticsItem* create() {
+ return new MediaAnalyticsItem();
+ }
static MediaAnalyticsItem* convert(mediametrics_handle_t);
static mediametrics_handle_t convert(MediaAnalyticsItem *);
@@ -94,13 +144,14 @@
void clear();
MediaAnalyticsItem *dup();
- // set the key discriminator for the record.
- // most often initialized as part of the constructor
- MediaAnalyticsItem &setKey(MediaAnalyticsItem::Key);
- const MediaAnalyticsItem::Key& getKey() const { return mKey; }
+ MediaAnalyticsItem &setKey(const char *key) {
+ mKey = key;
+ return *this;
+ }
+ const std::string& getKey() const { return mKey; }
- // # of attributes in the record
- int32_t count() const;
+ // # of properties in the record
+ size_t count() const { return mPropCount; }
template<typename S, typename T>
MediaAnalyticsItem &set(S key, T value) {
@@ -109,19 +160,19 @@
}
// set values appropriately
- MediaAnalyticsItem &setInt32(Attr key, int32_t value) {
+ MediaAnalyticsItem &setInt32(const char *key, int32_t value) {
return set(key, value);
}
- MediaAnalyticsItem &setInt64(Attr key, int64_t value) {
+ MediaAnalyticsItem &setInt64(const char *key, int64_t value) {
return set(key, value);
}
- MediaAnalyticsItem &setDouble(Attr key, double value) {
+ MediaAnalyticsItem &setDouble(const char *key, double value) {
return set(key, value);
}
- MediaAnalyticsItem &setRate(Attr key, int64_t count, int64_t duration) {
+ MediaAnalyticsItem &setRate(const char *key, int64_t count, int64_t duration) {
return set(key, std::make_pair(count, duration));
}
- MediaAnalyticsItem &setCString(Attr key, const char *value) {
+ MediaAnalyticsItem &setCString(const char *key, const char *value) {
return set(key, value);
}
@@ -133,16 +184,16 @@
return *this;
}
- MediaAnalyticsItem &addInt32(Attr key, int32_t value) {
+ MediaAnalyticsItem &addInt32(const char *key, int32_t value) {
return add(key, value);
}
- MediaAnalyticsItem &addInt64(Attr key, int64_t value) {
+ MediaAnalyticsItem &addInt64(const char *key, int64_t value) {
return add(key, value);
}
- MediaAnalyticsItem &addDouble(Attr key, double value) {
+ MediaAnalyticsItem &addDouble(const char *key, double value) {
return add(key, value);
}
- MediaAnalyticsItem &addRate(Attr key, int64_t count, int64_t duration) {
+ MediaAnalyticsItem &addRate(const char *key, int64_t count, int64_t duration) {
return add(key, std::make_pair(count, duration));
}
@@ -155,16 +206,16 @@
return prop != nullptr && prop->get(value);
}
- bool getInt32(Attr key, int32_t *value) const {
+ bool getInt32(const char *key, int32_t *value) const {
return get(key, value);
}
- bool getInt64(Attr key, int64_t *value) const {
+ bool getInt64(const char *key, int64_t *value) const {
return get(key, value);
}
- bool getDouble(Attr key, double *value) const {
+ bool getDouble(const char *key, double *value) const {
return get(key, value);
}
- bool getRate(Attr key, int64_t *count, int64_t *duration, double *rate) const {
+ bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
std::pair<int64_t, int64_t> value;
if (!get(key, &value)) return false;
if (count != nullptr) *count = value.first;
@@ -179,24 +230,29 @@
return true;
}
// Caller owns the returned string
- bool getCString(Attr key, char **value) const {
- return get(key, value);
+ bool getCString(const char *key, char **value) const {
+ const char *cs;
+ if (get(key, &cs)) {
+ *value = cs != nullptr ? strdup(cs) : nullptr;
+ return true;
+ }
+ return false;
}
- bool getString(Attr key, std::string *value) const {
+ bool getString(const char *key, std::string *value) const {
return get(key, value);
}
// Deliver the item to MediaMetrics
bool selfrecord();
- // remove indicated attributes and their values
- // filterNot() could also be called keepOnly()
- // return value is # attributes removed
- // XXX: perhaps 'remove' instead of 'filter'
- // XXX: filterNot would become 'keep'
- int32_t filter(int count, Attr attrs[]);
- int32_t filterNot(int count, Attr attrs[]);
- int32_t filter(Attr attr);
+ // remove indicated attributes and their values
+ // filterNot() could also be called keepOnly()
+ // return value is # attributes removed
+ // XXX: perhaps 'remove' instead of 'filter'
+ // XXX: filterNot would become 'keep'
+ size_t filter(size_t count, const char *attrs[]);
+ size_t filterNot(size_t count, const char *attrs[]);
+ size_t filter(const char *attr) { return filter(1, &attr); }
// below here are used on server side or to talk to server
// clients need not worry about these.
@@ -218,12 +274,26 @@
MediaAnalyticsItem &setPkgVersionCode(int64_t);
int64_t getPkgVersionCode() const;
- // our serialization code for binder calls
- int32_t writeToParcel(Parcel *);
- int32_t readFromParcel(const Parcel&);
+ // our serialization code for binder calls
+ status_t writeToParcel(Parcel *) const;
+ status_t readFromParcel(const Parcel&);
- // supports the stable interface
- bool dumpAttributes(char **pbuffer, size_t *plength);
+ status_t writeToByteString(char **bufferptr, size_t *length) const;
+ status_t readFromByteString(const char *bufferptr, size_t length);
+
+ static status_t writeToByteString(
+ const char *name, int32_t value, char **bufferpptr, char *bufferptrmax);
+ static status_t writeToByteString(
+ const char *name, int64_t value, char **bufferpptr, char *bufferptrmax);
+ static status_t writeToByteString(
+ const char *name, double value, char **bufferpptr, char *bufferptrmax);
+ static status_t writeToByteString(
+ const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax);
+ static status_t writeToByteString(
+ const char *name, char * const &value, char **bufferpptr, char *bufferptrmax);
+ struct none_t {}; // for kTypeNone
+ static status_t writeToByteString(
+ const char *name, const none_t &, char **bufferpptr, char *bufferptrmax);
std::string toString() const;
std::string toString(int version) const;
@@ -233,11 +303,6 @@
// are we collecting analytics data
static bool isEnabled();
- private:
- // handle Parcel version 0
- int32_t writeToParcel0(Parcel *);
- int32_t readFromParcel0(const Parcel&);
-
protected:
// merge fields from arg into this
@@ -246,18 +311,32 @@
// caller continues to own 'incoming'
bool merge(MediaAnalyticsItem *incoming);
+private:
+ // handle Parcel version 0
+ int32_t writeToParcel0(Parcel *) const;
+ int32_t readFromParcel0(const Parcel&);
+
// enabled 1, disabled 0
static constexpr const char * const EnabledProperty = "media.metrics.enabled";
static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
static const int EnabledProperty_default = 1;
- private:
-
// let's reuse a binder connection
static sp<IMediaAnalyticsService> sAnalyticsService;
static sp<IMediaAnalyticsService> getInstance();
static void dropInstance();
+ // checks equality even with nullptr.
+ static bool stringEquals(const char *a, const char *b) {
+ if (a == nullptr) {
+ return b == nullptr;
+ } else {
+ return b != nullptr && strcmp(a, b) == 0;
+ }
+ }
+
+public:
+
class Prop {
friend class MediaMetricsJNI; // TODO: remove this access
public:
@@ -271,7 +350,6 @@
} else {
mName = nullptr;
}
- mNameLen = other.mNameLen;
mType = other.mType;
switch (mType) {
case kTypeInt32:
@@ -287,7 +365,7 @@
u.CStringValue = strdup(other.u.CStringValue);
break;
case kTypeRate:
- u.rate = {other.u.rate.count, other.u.rate.duration};
+ u.rate = other.u.rate;
break;
case kTypeNone:
break;
@@ -297,11 +375,32 @@
}
return *this;
}
+ bool operator==(const Prop& other) const {
+ if (!stringEquals(mName, other.mName)
+ || mType != other.mType) return false;
+ switch (mType) {
+ case kTypeInt32:
+ return u.int32Value == other.u.int32Value;
+ case kTypeInt64:
+ return u.int64Value == other.u.int64Value;
+ case kTypeDouble:
+ return u.doubleValue == other.u.doubleValue;
+ case kTypeCString:
+ return stringEquals(u.CStringValue, other.u.CStringValue);
+ case kTypeRate:
+ return u.rate == other.u.rate;
+ case kTypeNone:
+ default:
+ return true;
+ }
+ }
+ bool operator!=(const Prop& other) const {
+ return !(*this == other);
+ }
void clear() {
free(mName);
mName = nullptr;
- mNameLen = 0;
clearValue();
}
void clearValue() {
@@ -322,29 +421,19 @@
void swap(Prop& other) {
std::swap(mName, other.mName);
- std::swap(mNameLen, other.mNameLen);
std::swap(mType, other.mType);
std::swap(u, other.u);
}
- void setName(const char *name, size_t len) {
+ void setName(const char *name) {
free(mName);
if (name != nullptr) {
- mName = (char *)malloc(len + 1);
- mNameLen = len;
- strncpy(mName, name, len);
- mName[len] = 0;
+ mName = strdup(name);
} else {
mName = nullptr;
- mNameLen = 0;
}
}
- bool isNamed(const char *name, size_t len) const {
- return len == mNameLen && memcmp(name, mName, len) == 0;
- }
-
- // TODO: remove duplicate but different definition
bool isNamed(const char *name) const {
return strcmp(name, mName) == 0;
}
@@ -369,9 +458,9 @@
return true;
}
template <>
- bool get(char** value) const {
+ bool get(const char** value) const {
if (mType != kTypeCString) return false;
- if (value != nullptr) *value = strdup(u.CStringValue);
+ if (value != nullptr) *value = u.CStringValue;
return true;
}
template <>
@@ -384,8 +473,7 @@
bool get(std::pair<int64_t, int64_t> *value) const {
if (mType != kTypeRate) return false;
if (value != nullptr) {
- value->first = u.rate.count;
- value->second = u.rate.duration;
+ *value = u.rate;
}
return true;
}
@@ -416,7 +504,13 @@
if (value == nullptr) {
u.CStringValue = nullptr;
} else {
- u.CStringValue = strdup(value);
+ size_t len = strlen(value);
+ if (len > UINT16_MAX - 1) {
+ len = UINT16_MAX - 1;
+ }
+ u.CStringValue = (char *)malloc(len + 1);
+ strncpy(u.CStringValue, value, len);
+ u.CStringValue[len] = 0;
}
}
template <>
@@ -456,33 +550,79 @@
template <>
void add(const std::pair<int64_t, int64_t>& value) {
if (mType == kTypeRate) {
- u.rate.count += value.first;
- u.rate.duration += value.second;
+ u.rate.first += value.first;
+ u.rate.second += value.second;
} else {
mType = kTypeRate;
- u.rate = {value.first, value.second};
+ u.rate = value;
}
}
- void writeToParcel(Parcel *data) const;
+ status_t writeToParcel(Parcel *data) const;
+ status_t readFromParcel(const Parcel& data);
void toString(char *buffer, size_t length) const;
+ size_t getByteStringSize() const;
+ status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const;
+ status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);
- // TODO: make private
+ // TODO: make private (and consider converting to std::variant)
// private:
char *mName = nullptr;
- size_t mNameLen = 0; // the strlen(), doesn't include the null
Type mType = kTypeNone;
- union {
+ union u__ {
+ u__() { zero(); }
+ u__(u__ &&other) {
+ *this = std::move(other);
+ }
+ u__& operator=(u__ &&other) {
+ memcpy(this, &other, sizeof(*this));
+ other.zero();
+ return *this;
+ }
+ void zero() { memset(this, 0, sizeof(*this)); }
+
int32_t int32Value;
int64_t int64Value;
double doubleValue;
char *CStringValue;
- struct { int64_t count, duration; } rate;
+ std::pair<int64_t, int64_t> rate;
} u;
};
- size_t findPropIndex(const char *name, size_t len) const;
+ class iterator {
+ public:
+ iterator(size_t pos, const MediaAnalyticsItem &_item)
+ : i(std::min(pos, _item.count()))
+ , item(_item) { }
+ iterator &operator++() {
+ i = std::min(i + 1, item.count());
+ return *this;
+ }
+ bool operator!=(iterator &other) const {
+ return i != other.i;
+ }
+ Prop &operator*() const {
+ return item.mProps[i];
+ }
+
+ private:
+ size_t i;
+ const MediaAnalyticsItem &item;
+ };
+
+ iterator begin() const {
+ return iterator(0, *this);
+ }
+ iterator end() const {
+ return iterator(SIZE_MAX, *this);
+ }
+
+private:
+
+ // TODO: make prop management class
+ size_t findPropIndex(const char *name) const;
Prop *findProp(const char *name) const;
+ Prop *allocateProp();
enum {
kGrowProps = 10
@@ -490,6 +630,7 @@
bool growProps(int increment = kGrowProps);
Prop *allocateProp(const char *name);
bool removeProp(const char *name);
+ Prop *allocateProp(const std::string& name) { return allocateProp(name.c_str()); }
size_t mPropCount = 0;
size_t mPropSize = 0;
@@ -499,7 +640,7 @@
uid_t mUid = -1;
std::string mPkgName;
int64_t mPkgVersionCode = 0;
- Key mKey{kKeyNone};
+ std::string mKey{kKeyNone};
nsecs_t mTimestamp = 0;
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 95c973a..4d9872a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -641,7 +641,7 @@
mAnalyticsItem->setUid(mClientUid);
}
} else {
- ALOGV("nothing to record (only %d fields)", mAnalyticsItem->count());
+ ALOGV("nothing to record (only %zu fields)", mAnalyticsItem->count());
}
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index 2d0c9e0..6788b56 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -19,8 +19,7 @@
#include "NuPlayerDrm.h"
-#include <binder/IServiceManager.h>
-#include <mediadrm/IMediaDrmService.h>
+#include <mediadrm/DrmUtils.h>
#include <utils/Log.h>
@@ -30,60 +29,13 @@
sp<IDrm> NuPlayerDrm::CreateDrm(status_t *pstatus)
{
- status_t &status = *pstatus;
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.drm"));
- ALOGV("CreateDrm binder %p", (binder != NULL ? binder.get() : 0));
-
- sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
- if (service == NULL) {
- ALOGE("CreateDrm failed at IMediaDrmService");
- return NULL;
- }
-
- sp<IDrm> drm = service->makeDrm();
- if (drm == NULL) {
- ALOGE("CreateDrm failed at makeDrm");
- return NULL;
- }
-
- // this is before plugin creation so NO_INIT is fine
- status = drm->initCheck();
- if (status != OK && status != NO_INIT) {
- ALOGE("CreateDrm failed drm->initCheck(): %d", status);
- return NULL;
- }
- return drm;
+ return DrmUtils::MakeDrm(pstatus);
}
sp<ICrypto> NuPlayerDrm::createCrypto(status_t *pstatus)
{
- status_t &status = *pstatus;
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.drm"));
- sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
- if (service == NULL) {
- status = UNKNOWN_ERROR;
- ALOGE("CreateCrypto failed at IMediaDrmService");
- return NULL;
- }
-
- sp<ICrypto> crypto = service->makeCrypto();
- if (crypto == NULL) {
- status = UNKNOWN_ERROR;
- ALOGE("createCrypto failed");
- return NULL;
- }
-
- // this is before plugin creation so NO_INIT is fine
- status = crypto->initCheck();
- if (status != OK && status != NO_INIT) {
- ALOGE("createCrypto failed crypto->initCheck(): %d", status);
- return NULL;
- }
-
- return crypto;
+ return DrmUtils::MakeCrypto(pstatus);
}
Vector<DrmUUID> NuPlayerDrm::parsePSSH(const void *pssh, size_t psshsize)
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 965e5a6..ef9d253 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2436,7 +2436,7 @@
}
rate = (OMX_U32)(rateFloat * 65536.0f + 0.5f);
} else {
- if (rateFloat > UINT_MAX) {
+ if (rateFloat > (float)UINT_MAX) {
return BAD_VALUE;
}
rate = (OMX_U32)(rateFloat);
@@ -3342,6 +3342,7 @@
{ MEDIA_MIMETYPE_VIDEO_VP9, OMX_VIDEO_CodingVP9 },
{ MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, OMX_VIDEO_CodingDolbyVision },
{ MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC, OMX_VIDEO_CodingImageHEIC },
+ { MEDIA_MIMETYPE_VIDEO_AV1, OMX_VIDEO_CodingAV1 },
};
static status_t GetVideoCodingTypeFromMime(
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 4f9bc6d..24608a7 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -281,7 +281,7 @@
it = mTimers.erase(it);
} else {
if (mPlaybackRate != 0.0
- && (double)diffMediaUs < INT64_MAX * (double)mPlaybackRate) {
+ && (double)diffMediaUs < (double)INT64_MAX * (double)mPlaybackRate) {
int64_t targetRealUs = diffMediaUs / (double)mPlaybackRate;
if (targetRealUs < nextLapseRealUs) {
nextLapseRealUs = targetRealUs;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ac4d087..a1e4d43 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -751,6 +751,7 @@
{ "temporal-layer-id", kKeyTemporalLayerId },
{ "thumbnail-width", kKeyThumbnailWidth },
{ "thumbnail-height", kKeyThumbnailHeight },
+ { "track-id", kKeyTrackID },
{ "valid-samples", kKeyValidSamples },
}
};
@@ -958,12 +959,6 @@
msg->setInt32("is-sync-frame", 1);
}
- // this only needs to be translated from meta to message as it is an extractor key
- int32_t trackID;
- if (meta->findInt32(kKeyTrackID, &trackID)) {
- msg->setInt32("track-id", trackID);
- }
-
const char *lang;
if (meta->findCString(kKeyMediaLanguage, &lang)) {
msg->setString("language", lang);
@@ -1874,7 +1869,7 @@
if (msg->findInt32("frame-rate", &fps) && fps > 0) {
meta->setInt32(kKeyFrameRate, fps);
} else if (msg->findFloat("frame-rate", &fpsFloat)
- && fpsFloat >= 1 && fpsFloat <= INT32_MAX) {
+ && fpsFloat >= 1 && fpsFloat <= (float)INT32_MAX) {
// truncate values to distinguish between e.g. 24 vs 23.976 fps
meta->setInt32(kKeyFrameRate, (int32_t)fpsFloat);
}
@@ -1909,25 +1904,24 @@
meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
} else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
if (msg->findBuffer("csd-2", &csd2)) {
- meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
-
- size_t dvcc_size = 1024;
- uint8_t dvcc[dvcc_size];
- memcpy(dvcc, csd2->data(), dvcc_size);
- const uint8_t profile = dvcc[2] >> 1;
-
- if (profile > 1 && profile < 9) {
- std::vector<uint8_t> hvcc(csd0size + 1024);
- size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
- meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
- } else if (DolbyVisionProfileDvav110 == profile) {
- meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
- } else {
- sp<ABuffer> csd1;
- if (msg->findBuffer("csd-1", &csd1)) {
- std::vector<char> avcc(csd0size + csd1->size() + 1024);
- size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
- meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
+ //dvcc should be 24
+ if (csd2->size() == 24) {
+ meta->setData(kKeyDVCC, kTypeDVCC, csd2->data(), csd2->size());
+ uint8_t *dvcc = csd2->data();
+ const uint8_t profile = dvcc[2] >> 1;
+ if (profile > 1 && profile < 9) {
+ std::vector<uint8_t> hvcc(csd0size + 1024);
+ size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
+ meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
+ } else if (DolbyVisionProfileDvav110 == profile) {
+ meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
+ } else {
+ sp<ABuffer> csd1;
+ if (msg->findBuffer("csd-1", &csd1)) {
+ std::vector<char> avcc(csd0size + csd1->size() + 1024);
+ size_t outsize = reassembleAVCC(csd0, csd1, avcc.data());
+ meta->setData(kKeyAVCC, kTypeAVCC, avcc.data(), outsize);
+ }
}
}
} else {
diff --git a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
index adb0dd4..f9d91b1 100644
--- a/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
+++ b/media/libstagefright/codecs/mp3dec/src/pv_mp3dec_fxd_op_c_equivalent.h
@@ -44,7 +44,7 @@
#endif
#include "pvmp3_audio_type_defs.h"
-#define Qfmt_31(a) (Int32)((float)(a)*0x7FFFFFFF)
+#define Qfmt_31(a) (Int32)((float)(a)*(float)0x7FFFFFFF)
#define Qfmt15(x) (Int16)((x)*((Int32)1<<15) + ((x)>=0?0.5F:-0.5F))
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
index af738ba..6c8102b 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_alias_reduction.cpp
@@ -169,7 +169,7 @@
int32 i, j;
- *used_freq_lines = fxp_mul32_Q32(*used_freq_lines << 16, (int32)(0x7FFFFFFF / (float)18 - 1.0f)) >> 15;
+ *used_freq_lines = fxp_mul32_Q32(*used_freq_lines << 16, (int32)((float)0x7FFFFFFF / (float)18 - 1.0f)) >> 15;
if (gr_info->window_switching_flag && gr_info->block_type == 2)
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
index bbb247d..9cd0e91 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_dct_9.cpp
@@ -77,7 +77,7 @@
; Include all pre-processor statements here. Include conditional
; compile variables also.
----------------------------------------------------------------------------*/
-#define Qfmt31(a) (int32)((a)*(0x7FFFFFFF))
+#define Qfmt31(a) (int32)((a)*((float)0x7FFFFFFF))
#define cos_pi_9 Qfmt31( 0.93969262078591f)
#define cos_2pi_9 Qfmt31( 0.76604444311898f)
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index cac1af9..bb66f4c 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -954,7 +954,7 @@
CHECK_GE(space2, 0);
method->setTo(request, 0, space1);
- url->setTo(request, space1 + 1, space2 - space1);
+ url->setTo(request, space1 + 1, space2 - space1 - 1);
}
void ARTSPConnection::addAuthentication(AString *request) {
diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp
index 792fc00..741e58b 100644
--- a/media/ndk/NdkMediaCrypto.cpp
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -26,9 +26,8 @@
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/StrongPointer.h>
-#include <binder/IServiceManager.h>
+#include <mediadrm/DrmUtils.h>
#include <mediadrm/ICrypto.h>
-#include <mediadrm/IMediaDrmService.h>
#include <android_util_Binder.h>
#include <jni.h>
@@ -36,19 +35,7 @@
using namespace android;
static sp<ICrypto> makeCrypto() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.drm"));
-
- sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
- if (service == NULL) {
- return NULL;
- }
-
- sp<ICrypto> crypto = service->makeCrypto();
- if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) {
- return NULL;
- }
- return crypto;
+ return DrmUtils::MakeCrypto();
}
struct AMediaCrypto {
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 842216c..b78373d 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -29,6 +29,7 @@
#include <android-base/properties.h>
#include <binder/PermissionController.h>
+#include <mediadrm/DrmUtils.h>
#include <mediadrm/IDrm.h>
#include <mediadrm/IDrmClient.h>
#include <media/stagefright/MediaErrors.h>
@@ -71,12 +72,27 @@
mKeysChangeListener = listener;
}
- void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
+ void sendEvent(
+ DrmPlugin::EventType eventType,
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const hardware::hidl_vec<uint8_t> &data) override;
+
+ void sendExpirationUpdate(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ int64_t expiryTimeInMS) override;
+
+ void sendKeysChange(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const std::vector<DrmKeyStatus> &keyStatusList,
+ bool hasNewUsableKey) override;
+
+ void sendSessionLostState(
+ const hardware::hidl_vec<uint8_t> &) override {}
+
};
struct AMediaDrm {
sp<IDrm> mDrm;
- sp<IDrmClient> mDrmClient;
List<idvec_t> mIds;
KeyedVector<String8, String8> mQueryResults;
Vector<uint8_t> mKeyRequest;
@@ -88,71 +104,52 @@
sp<DrmListener> mListener;
};
-void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
- if (!mEventListener || !mExpirationUpdateListener || !mKeysChangeListener) {
- ALOGE("No listeners are specified");
+void DrmListener::sendExpirationUpdate(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ int64_t expiryTimeInMS) {
+ if (!mExpirationUpdateListener) {
+ ALOGE("No ExpirationUpdateListener specified");
return;
}
- obj->setDataPosition(0);
+ if (expiryTimeInMS >= 0) {
+ AMediaDrmSessionId asid = {sessionId.data(), sessionId.size()};
+ (*mExpirationUpdateListener)(mObj, &asid, expiryTimeInMS);
+ } else {
+ ALOGE("expiry time negative, status=%" PRId64 "", expiryTimeInMS);
+ }
+}
- AMediaDrmSessionId sessionId = {NULL, 0};
- int32_t sessionIdSize = obj->readInt32();
- if (sessionIdSize <= 0) {
- ALOGE("Invalid session id size");
+void DrmListener::sendKeysChange(
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const std::vector<DrmKeyStatus> &keyStatusList,
+ bool hasNewUsableKey) {
+ if (!mKeysChangeListener) {
+ ALOGE("No KeysChangeListener specified");
return;
}
- std::unique_ptr<uint8_t[]> sessionIdData(new uint8_t[sessionIdSize]);
- sessionId.ptr = sessionIdData.get();
- sessionId.length = sessionIdSize;
- status_t err = obj->read(sessionIdData.get(), sessionId.length);
- if (err != OK) {
- ALOGE("Failed to read session id, error=%d", err);
- return;
- }
-
- if (DrmPlugin::kDrmPluginEventExpirationUpdate == eventType) {
- int64_t expiryTimeInMS = obj->readInt64();
- if (expiryTimeInMS >= 0) {
- (*mExpirationUpdateListener)(mObj, &sessionId, expiryTimeInMS);
- } else {
- ALOGE("Failed to read expiry time, status=%" PRId64 "", expiryTimeInMS);
- }
- return;
- } else if (DrmPlugin::kDrmPluginEventKeysChange == eventType) {
- int32_t numKeys = 0;
- err = obj->readInt32(&numKeys);
- if (err != OK) {
- ALOGE("Failed to read number of keys status, error=%d", err);
- return;
- }
-
- Vector<AMediaDrmKeyStatus> keysStatus;
- std::vector<std::unique_ptr<uint8_t[]> > dataPointers;
+ Vector<AMediaDrmKeyStatus> keysStatus;
+ for (const auto &drmKeyStatus : keyStatusList) {
AMediaDrmKeyStatus keyStatus;
+ keyStatus.keyId.ptr = drmKeyStatus.keyId.data();
+ keyStatus.keyId.length = drmKeyStatus.keyId.size();
+ keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(drmKeyStatus.type);
+ keysStatus.push(keyStatus);
+ }
- for (size_t i = 0; i < numKeys; ++i) {
- keyStatus.keyId.ptr = nullptr;
- keyStatus.keyId.length = 0;
- int32_t idSize = obj->readInt32();
- if (idSize > 0) {
- std::unique_ptr<uint8_t[]> data(new uint8_t[idSize]);
- err = obj->read(data.get(), idSize);
- if (err != OK) {
- ALOGE("Failed to read key data, error=%d", err);
- return;
- }
- keyStatus.keyId.ptr = data.get();
- keyStatus.keyId.length = idSize;
- dataPointers.push_back(std::move(data));
- }
- keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(obj->readInt32());
- keysStatus.push(keyStatus);
- }
+ AMediaDrmSessionId asid = {sessionId.data(), sessionId.size()};
+ int32_t numKeys = keyStatusList.size();
+ (*mKeysChangeListener)(mObj, &asid, keysStatus.array(), numKeys, hasNewUsableKey);
+ return;
+}
- bool hasNewUsableKey = obj->readInt32();
- (*mKeysChangeListener)(mObj, &sessionId, keysStatus.array(), numKeys, hasNewUsableKey);
+void DrmListener::sendEvent(
+ DrmPlugin::EventType eventType,
+ const hardware::hidl_vec<uint8_t> &sessionId,
+ const hardware::hidl_vec<uint8_t> &data) {
+ if (!mEventListener) {
+ ALOGE("No EventListener specified");
return;
}
@@ -176,23 +173,17 @@
ndkEventType = EVENT_SESSION_RECLAIMED;
break;
default:
- ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
+ ALOGE("Invalid event DrmPlugin::EventType %d, ignored", eventType);
return;
}
- int32_t dataSize = obj->readInt32();
- uint8_t *data = NULL;
+ AMediaDrmSessionId asid = {sessionId.data(), sessionId.size()};
+ int32_t dataSize = data.size();
+ const uint8_t *dataPtr = data.data();
if (dataSize > 0) {
- data = new uint8_t[dataSize];
- err = obj->read(data, dataSize);
- if (err == OK) {
- (*mEventListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
- } else {
- ALOGE("Failed to read event data, error=%d", err);
- }
- delete [] data;
+ (*mEventListener)(mObj, &asid, ndkEventType, 0, dataPtr, dataSize);
} else {
- ALOGE("Error reading parcel: invalid event data size=%d", dataSize);
+ ALOGE("invalid event data size=%d", dataSize);
}
}
@@ -268,19 +259,7 @@
}
static sp<IDrm> CreateDrm() {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.drm"));
-
- sp<IMediaDrmService> service = interface_cast<IMediaDrmService>(binder);
- if (service == NULL) {
- return NULL;
- }
-
- sp<IDrm> drm = service->makeDrm();
- if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
- return NULL;
- }
- return drm;
+ return DrmUtils::MakeDrm();
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index eba0b20..9d80425 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1573,7 +1573,7 @@
proposed.format = format;
sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
- size_t frames;
+ size_t frames = 0;
for (;;) {
// Note: config is currently a const parameter for get_input_buffer_size()
// but we use a copy from proposed in case config changes from the call.
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 0d3e614..bd73cde 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_AUDIOPOLICY_INTERFACE_H
#define ANDROID_AUDIOPOLICY_INTERFACE_H
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioSystem.h>
#include <media/AudioPolicy.h>
#include <media/DeviceDescriptorBase.h>
@@ -270,6 +271,8 @@
virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa,
volume_group_t &volumeGroup) = 0;
+
+ virtual bool isCallScreenModeSupported() = 0;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 56596f5..e59386f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -45,7 +45,8 @@
mAvailableOutputDevices(availableOutputDevices),
mAvailableInputDevices(availableInputDevices),
mDefaultOutputDevice(defaultOutputDevice),
- mIsSpeakerDrcEnabled(false)
+ mIsSpeakerDrcEnabled(false),
+ mIsCallScreenModeSupported(false)
{}
const std::string& getSource() const {
@@ -95,6 +96,14 @@
mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
}
+ bool isCallScreenModeSupported() const { return mIsCallScreenModeSupported; }
+
+ void setCallScreenModeSupported(bool isCallScreenModeSupported)
+ {
+ mIsCallScreenModeSupported = isCallScreenModeSupported;
+ }
+
+
const HwModuleCollection getHwModules() const { return mHwModules; }
const DeviceVector &getAvailableInputDevices() const
@@ -189,6 +198,7 @@
// DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
// Note: remove also speaker_drc_enabled from global configuration of XML config file.
bool mIsSpeakerDrcEnabled;
+ bool mIsCallScreenModeSupported;
SurroundFormats mSurroundFormats;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 094f506..fc79ab1 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -18,6 +18,7 @@
#include "DeviceDescriptor.h"
#include <utils/RefBase.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <media/AudioPolicy.h>
#include <utils/Vector.h>
#include <system/audio.h>
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 7faf90e..a6562d7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -33,9 +33,13 @@
{
public:
// Note that empty name refers by convention to a generic device.
- explicit DeviceDescriptor(audio_devices_t type, const std::string &tagName = "");
- DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
- const std::string &tagName = "");
+ explicit DeviceDescriptor(audio_devices_t type);
+ DeviceDescriptor(audio_devices_t type, const std::string &tagName,
+ const FormatVector &encodedFormats = FormatVector{});
+ DeviceDescriptor(audio_devices_t type, const std::string &tagName,
+ const std::string &address, const FormatVector &encodedFormats = FormatVector{});
+ DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr, const std::string &tagName = "",
+ const FormatVector &encodedFormats = FormatVector{});
virtual ~DeviceDescriptor() {}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 6f8ea36..20c0a24 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -455,9 +455,9 @@
}
// check if this mix goes to a device in the list of devices
bool deviceMatch = false;
+ const AudioDeviceTypeAddr mixDevice(mix->mDeviceType, mix->mDeviceAddress.string());
for (size_t j = 0; j < devices.size(); j++) {
- if (devices[j].mType == mix->mDeviceType
- && devices[j].mAddress == mix->mDeviceAddress) {
+ if (mixDevice.equals(devices[j])) {
deviceMatch = true;
break;
}
@@ -522,7 +522,7 @@
}
}
if (ruleAllowsUid) {
- devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress));
+ devices.add(AudioDeviceTypeAddr(mix->mDeviceType, mix->mDeviceAddress.string()));
}
}
return NO_ERROR;
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 0587041..86dbba8 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -26,14 +26,30 @@
namespace android {
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const std::string &tagName) :
- DeviceDescriptor(type, FormatVector{}, tagName)
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type) :
+ DeviceDescriptor(type, "" /*tagName*/)
{
}
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const FormatVector &encodedFormats,
- const std::string &tagName) :
- DeviceDescriptorBase(type), mTagName(tagName), mEncodedFormats(encodedFormats)
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type,
+ const std::string &tagName,
+ const FormatVector &encodedFormats) :
+ DeviceDescriptor(type, tagName, "" /*address*/, encodedFormats)
+{
+}
+
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type,
+ const std::string &tagName,
+ const std::string &address,
+ const FormatVector &encodedFormats) :
+ DeviceDescriptor(AudioDeviceTypeAddr(type, address), tagName, encodedFormats)
+{
+}
+
+DeviceDescriptor::DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr,
+ const std::string &tagName,
+ const FormatVector &encodedFormats) :
+ DeviceDescriptorBase(deviceTypeAddr), mTagName(tagName), mEncodedFormats(encodedFormats)
{
mCurrentEncodedFormat = AUDIO_FORMAT_DEFAULT;
/* If framework runs against a pre 5.0 Audio HAL, encoded formats are absent from the config.
@@ -41,7 +57,7 @@
* For now, the workaround to remove AC3 and IEC61937 support on HDMI is to declare
* something like 'encodedFormats="AUDIO_FORMAT_PCM_16_BIT"' on the HDMI devicePort.
*/
- if (type == AUDIO_DEVICE_OUT_HDMI && mEncodedFormats.empty()) {
+ if (mDeviceTypeAddr.mType == AUDIO_DEVICE_OUT_HDMI && mEncodedFormats.empty()) {
mEncodedFormats.push_back(AUDIO_FORMAT_AC3);
mEncodedFormats.push_back(AUDIO_FORMAT_IEC61937);
}
@@ -76,7 +92,7 @@
return false;
}
- return (mDeviceType == other->mDeviceType) && (mAddress == other->mAddress) &&
+ return mDeviceTypeAddr.equals(other->mDeviceTypeAddr) &&
checkEqual(mEncodedFormats, other->mEncodedFormats);
}
@@ -135,7 +151,7 @@
void DeviceDescriptor::toAudioPort(struct audio_port *port) const
{
- ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceType);
+ ALOGV("DeviceDescriptor::toAudioPort() handle %d type %08x", mId, mDeviceTypeAddr.mType);
DeviceDescriptorBase::toAudioPort(port);
port->ext.device.hw_module = getModuleHandle();
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 0b4d3d4..886e4c9 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -49,8 +49,7 @@
profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
config->sample_rate));
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
- devDesc->setAddress(address.string());
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, "" /*tagName*/, address.string());
addDynamicDevice(devDesc);
// Reciprocally attach the device to the module
devDesc->attach(this);
@@ -117,8 +116,7 @@
profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
config->sample_rate));
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
- devDesc->setAddress(address.string());
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, "" /*tagName*/, address.string());
addDynamicDevice(devDesc);
// Reciprocally attach the device to the module
devDesc->attach(this);
@@ -360,9 +358,9 @@
address);
return nullptr;
}
- sp<DeviceDescriptor> device = new DeviceDescriptor(type, name);
+
+ sp<DeviceDescriptor> device = new DeviceDescriptor(type, name, address);
device->setName(name);
- device->setAddress(address);
device->setEncodedFormat(encodedFormat);
// Add the device to the list of dynamic devices
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 3b27cf6..4376802 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -199,6 +199,7 @@
struct Attributes
{
static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
+ static constexpr const char *callScreenModeSupported= "call_screen_mode_supported";
};
static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
@@ -511,13 +512,8 @@
if (!encodedFormatsLiteral.empty()) {
encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
}
- Element deviceDesc = new DeviceDescriptor(type, encodedFormats, name);
-
std::string address = getXmlAttribute(cur, Attributes::address);
- if (!address.empty()) {
- ALOGV("%s: address=%s for %s", __func__, address.c_str(), name.c_str());
- deviceDesc->setAddress(address);
- }
+ Element deviceDesc = new DeviceDescriptor(type, name, address, encodedFormats);
AudioProfileTraits::Collection profiles;
status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
@@ -685,14 +681,17 @@
{
for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
- std::string speakerDrcEnabled =
- getXmlAttribute(cur, Attributes::speakerDrcEnabled);
- bool isSpeakerDrcEnabled;
- if (!speakerDrcEnabled.empty() &&
- convertTo<std::string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
- config->setSpeakerDrcEnabled(isSpeakerDrcEnabled);
+ bool value;
+ std::string attr = getXmlAttribute(cur, Attributes::speakerDrcEnabled);
+ if (!attr.empty() &&
+ convertTo<std::string, bool>(attr, value)) {
+ config->setSpeakerDrcEnabled(value);
}
- return NO_ERROR;
+ attr = getXmlAttribute(cur, Attributes::callScreenModeSupported);
+ if (!attr.empty() &&
+ convertTo<std::string, bool>(attr, value)) {
+ config->setCallScreenModeSupported(value);
+ }
}
}
return NO_ERROR;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 3223530..3ea69f1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -682,8 +682,8 @@
* Switching to or from incall state or switching between telephony and VoIP lead to force
* routing command.
*/
- bool force = ((is_state_in_call(oldState) != is_state_in_call(state))
- || (is_state_in_call(state) && (state != oldState)));
+ bool force = ((isStateInCall(oldState) != isStateInCall(state))
+ || (isStateInCall(state) && (state != oldState)));
// check for device and output changes triggered by new phone state
checkForDeviceAndOutputChanges();
@@ -1015,7 +1015,7 @@
if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX) &&
(*stream == AUDIO_STREAM_MUSIC || resultAttr->usage == AUDIO_USAGE_VOICE_COMMUNICATION) &&
audio_is_linear_pcm(config->format) &&
- isInCall()) {
+ isCallAudioAccessible()) {
if (requestedPortId != AUDIO_PORT_HANDLE_NONE) {
*flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
*isRequestedDeviceForExclusiveUse = true;
@@ -3058,13 +3058,13 @@
// reevaluate outputs for all given devices
for (size_t i = 0; i < devices.size(); i++) {
sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
- devices[i].mType, devices[i].mAddress, String8(),
+ devices[i].mType, devices[i].mAddress.c_str(), String8(),
AUDIO_FORMAT_DEFAULT);
SortedVector<audio_io_handle_t> outputs;
if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
outputs) != NO_ERROR) {
ALOGE("setUidDeviceAffinities() error in checkOutputsForDevice for device=%08x"
- " addr=%s", devices[i].mType, devices[i].mAddress.string());
+ " addr=%s", devices[i].mType, devices[i].mAddress.c_str());
return INVALID_OPERATION;
}
}
@@ -4207,6 +4207,12 @@
return false;
}
+bool AudioPolicyManager::isCallScreenModeSupported()
+{
+ return getConfig().isCallScreenModeSupported();
+}
+
+
status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
@@ -6062,6 +6068,14 @@
return is_state_in_call(state);
}
+bool AudioPolicyManager::isCallAudioAccessible()
+{
+ audio_mode_t mode = mEngine->getPhoneState();
+ return (mode == AUDIO_MODE_IN_CALL)
+ || (mode == AUDIO_MODE_IN_COMMUNICATION)
+ || (mode == AUDIO_MODE_CALL_SCREEN);
+}
+
void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc)
{
for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 707e4b0..500b636 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -306,6 +306,8 @@
return volumeGroup != VOLUME_GROUP_NONE ? NO_ERROR : BAD_VALUE;
}
+ bool isCallScreenModeSupported() override;
+
status_t initialize();
protected:
@@ -476,6 +478,8 @@
virtual bool isInCall();
// true if given state represents a device in a telephony or VoIP call
virtual bool isStateInCall(int state);
+ // true if playback to call TX or capture from call RX is possible
+ bool isCallAudioAccessible();
// when a device is connected, checks if an open output can be routed
// to this device. If none is open, tries to open one of the available outputs.
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 875f51d..10355bf 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -1329,4 +1329,15 @@
return NO_ERROR;
}
+bool AudioPolicyService::isCallScreenModeSupported()
+{
+ if (mAudioPolicyManager == NULL) {
+ ALOGW("%s, mAudioPolicyManager == NULL", __func__);
+ return false;
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ return mAudioPolicyManager->isCallScreenModeSupported();
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 2319838..c8d7d0c 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -977,7 +977,8 @@
void AudioPolicyService::UidPolicy::onUidStateChanged(uid_t uid,
int32_t procState,
- int64_t procStateSeq __unused) {
+ int64_t procStateSeq __unused,
+ int32_t capability __unused) {
if (procState != ActivityManager::PROCESS_STATE_UNKNOWN) {
updateUid(&mCachedUids, uid, true, procState, true);
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 175fed4..2bd02c8 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -259,6 +259,8 @@
virtual status_t setRttEnabled(bool enabled);
+ bool isCallScreenModeSupported() override;
+
status_t doStopOutput(audio_port_handle_t portId);
void doReleaseOutput(audio_port_handle_t portId);
@@ -371,7 +373,8 @@
void onUidActive(uid_t uid) override;
void onUidGone(uid_t uid, bool disabled) override;
void onUidIdle(uid_t uid, bool disabled) override;
- void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq);
+ void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+ int32_t capability);
void addOverrideUid(uid_t uid, bool active) { updateOverrideUid(uid, active, true); }
void removeOverrideUid(uid_t uid) { updateOverrideUid(uid, false, false); }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a02178e..c10adbb 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -2855,7 +2855,7 @@
}
void CameraService::UidPolicy::onUidStateChanged(uid_t uid, int32_t procState,
- int64_t /*procStateSeq*/) {
+ int64_t procStateSeq __unused, int32_t capability __unused) {
bool procStateChange = false;
{
Mutex::Autolock _l(mUidLock);
@@ -3448,10 +3448,21 @@
ALOGE("%s: Invalid camera id %s, skipping", __FUNCTION__, cameraId.string());
return;
}
-
+ bool supportsHAL3 = false;
+ // supportsCameraApi also holds mInterfaceMutex, we can't call it in the
+ // HIDL onStatusChanged wrapper call (we'll hold mStatusListenerLock and
+ // mInterfaceMutex together, which can lead to deadlocks)
+ binder::Status sRet =
+ supportsCameraApi(String16(cameraId), hardware::ICameraService::API_VERSION_2,
+ &supportsHAL3);
+ if (!sRet.isOk()) {
+ ALOGW("%s: Failed to determine if device supports HAL3 %s, supportsCameraApi call failed",
+ __FUNCTION__, cameraId.string());
+ return;
+ }
// Update the status for this camera state, then send the onStatusChangedCallbacks to each
// of the listeners with both the mStatusStatus and mStatusListenerLock held
- state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind]
+ state->updateStatus(status, cameraId, rejectSourceStates, [this, &deviceKind, &supportsHAL3]
(const String8& cameraId, StatusInternal status) {
if (status != StatusInternal::ENUMERATING) {
@@ -3473,9 +3484,11 @@
Mutex::Autolock lock(mStatusListenerLock);
for (auto& listener : mListenerList) {
- if (shouldSkipStatusUpdates(deviceKind, listener->isVendorListener(),
- listener->getListenerPid(), listener->getListenerUid())) {
- ALOGV("Skipping camera discovery callback for system-only camera %s",
+ bool isVendorListener = listener->isVendorListener();
+ if (shouldSkipStatusUpdates(deviceKind, isVendorListener,
+ listener->getListenerPid(), listener->getListenerUid()) ||
+ (isVendorListener && !supportsHAL3)) {
+ ALOGV("Skipping discovery callback for system-only camera/HAL1 device %s",
cameraId.c_str());
continue;
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8765fbf..829a3ee 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -574,7 +574,8 @@
void onUidGone(uid_t uid, bool disabled);
void onUidActive(uid_t uid);
void onUidIdle(uid_t uid, bool disabled);
- void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq);
+ void onUidStateChanged(uid_t uid, int32_t procState, int64_t procStateSeq,
+ int32_t capability);
void addOverrideUid(uid_t uid, String16 callingPackage, bool active);
void removeOverrideUid(uid_t uid, String16 callingPackage);
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 88799f9..0c01a91 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -265,7 +265,7 @@
Mutex::Autolock l(mInputMutex);
while (!mStartCapture) {
res = mStartCaptureSignal.waitRelative(mInputMutex,
- kWaitDuration);
+ kIdleWaitDuration);
if (res == TIMED_OUT) break;
}
if (mStartCapture) {
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 727dd53..9475a39 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -111,6 +111,7 @@
* Internal to CaptureSequencer
*/
static const nsecs_t kWaitDuration = 100000000; // 100 ms
+ static const nsecs_t kIdleWaitDuration = 10000000; // 10 ms
static const int kMaxTimeoutsForPrecaptureStart = 10; // 1 sec
static const int kMaxTimeoutsForPrecaptureEnd = 20; // 2 sec
static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 26459f9..bf4d1c8 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -597,7 +597,8 @@
// to look up timestamp.
int64_t bufferTime = -1;
if (mCodecOutputBufferTimestamps.empty()) {
- ALOGE("%s: Failed to find buffer timestamp for codec output buffer!", __FUNCTION__);
+ ALOGV("%s: Failed to find buffer timestamp for codec output buffer!", __FUNCTION__);
+ break;
} else {
// Direct mapping between camera timestamp (in ns) and codec timestamp (in us).
bufferTime = mCodecOutputBufferTimestamps.front();
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 74cfe42..1daa035 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -191,6 +191,14 @@
_hidl_cb(status, {});
return Void();
}
+ cameraStatusAndIds.erase(std::remove_if(cameraStatusAndIds.begin(), cameraStatusAndIds.end(),
+ [this](const hardware::CameraStatus& s) {
+ bool supportsHAL3 = false;
+ binder::Status sRet =
+ mAidlICameraService->supportsCameraApi(String16(s.cameraId),
+ hardware::ICameraService::API_VERSION_2, &supportsHAL3);
+ return !sRet.isOk() || !supportsHAL3;
+ }), cameraStatusAndIds.end());
hidl_vec<HCameraStatusAndId> hCameraStatusAndIds;
//Convert cameraStatusAndIds to HIDL and call callback
convertToHidl(cameraStatusAndIds, &hCameraStatusAndIds);
diff --git a/services/mediaanalytics/tests/mediametrics_tests.cpp b/services/mediaanalytics/tests/mediametrics_tests.cpp
index 7a6f5a4..09ca114 100644
--- a/services/mediaanalytics/tests/mediametrics_tests.cpp
+++ b/services/mediaanalytics/tests/mediametrics_tests.cpp
@@ -160,6 +160,27 @@
}
}
+TEST(mediametrics_tests, superbig_item_removal2) {
+ MediaAnalyticsItem item("TheOne");
+ constexpr size_t count = 10000;
+
+ for (size_t i = 0; i < count; ++i) {
+ item.setInt32(std::to_string(i).c_str(), i);
+ }
+ static const char *attrs[] = { "1", };
+ item.filterNot(1, attrs);
+
+ for (size_t i = 0; i < count; ++i) {
+ int32_t i32;
+ if (i == 1) { // check to see that there is only one
+ ASSERT_TRUE(item.getInt32(std::to_string(i).c_str(), &i32));
+ ASSERT_EQ((int32_t)i, i32);
+ } else {
+ ASSERT_FALSE(item.getInt32(std::to_string(i).c_str(), &i32));
+ }
+ }
+}
+
TEST(mediametrics_tests, item_transmutation) {
MediaAnalyticsItem item("Alchemist's Stone");
@@ -175,3 +196,88 @@
ASSERT_TRUE(item.getInt32("convert", &i32)); // check it is i32 and 2 (123 is discarded).
ASSERT_EQ(2, i32);
}
+
+TEST(mediametrics_tests, item_binderization) {
+ MediaAnalyticsItem item;
+ item.setInt32("i32", 1)
+ .setInt64("i64", 2)
+ .setDouble("double", 3.1)
+ .setCString("string", "abc")
+ .setRate("rate", 11, 12);
+
+ Parcel p;
+ item.writeToParcel(&p);
+
+ p.setDataPosition(0); // rewind for reading
+ MediaAnalyticsItem item2;
+ item2.readFromParcel(p);
+
+ ASSERT_EQ(item, item2);
+}
+
+TEST(mediametrics_tests, item_byteserialization) {
+ MediaAnalyticsItem item;
+ item.setInt32("i32", 1)
+ .setInt64("i64", 2)
+ .setDouble("double", 3.1)
+ .setCString("string", "abc")
+ .setRate("rate", 11, 12);
+
+ char *data;
+ size_t length;
+ ASSERT_EQ(0, item.writeToByteString(&data, &length));
+ ASSERT_GT(length, (size_t)0);
+
+ MediaAnalyticsItem item2;
+ item2.readFromByteString(data, length);
+
+ printf("item: %s\n", item.toString().c_str());
+ printf("item2: %s\n", item2.toString().c_str());
+ ASSERT_EQ(item, item2);
+
+ free(data);
+}
+
+TEST(mediametrics_tests, item_iteration) {
+ MediaAnalyticsItem item;
+ item.setInt32("i32", 1)
+ .setInt64("i64", 2)
+ .setDouble("double", 3.125)
+ .setCString("string", "abc")
+ .setRate("rate", 11, 12);
+
+ int mask = 0;
+ for (auto &prop : item) {
+ const char *name = prop.getName();
+ if (!strcmp(name, "i32")) {
+ int32_t i32;
+ ASSERT_TRUE(prop.get(&i32));
+ ASSERT_EQ(1, i32);
+ mask |= 1;
+ } else if (!strcmp(name, "i64")) {
+ int64_t i64;
+ ASSERT_TRUE(prop.get(&i64));
+ ASSERT_EQ(2, i64);
+ mask |= 2;
+ } else if (!strcmp(name, "double")) {
+ double d;
+ ASSERT_TRUE(prop.get(&d));
+ ASSERT_EQ(3.125, d);
+ mask |= 4;
+ } else if (!strcmp(name, "string")) {
+ const char *s;
+ ASSERT_TRUE(prop.get(&s));
+ ASSERT_EQ(0, strcmp(s, "abc"));
+ mask |= 8;
+ } else if (!strcmp(name, "rate")) {
+ std::pair<int64_t, int64_t> r;
+ ASSERT_TRUE(prop.get(&r));
+ ASSERT_EQ(11, r.first);
+ ASSERT_EQ(12, r.second);
+ mask |= 16;
+ } else {
+ FAIL();
+ }
+ }
+ ASSERT_EQ(31, mask);
+}
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index 36042a4..3141c31 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -62,5 +62,8 @@
src: "seccomp_policy/mediacodec-x86.policy",
},
},
- required: ["crash_dump.policy"],
+ required: [
+ "crash_dump.policy",
+ "code_coverage.policy",
+ ],
}
diff --git a/services/mediacodec/Android.mk b/services/mediacodec/Android.mk
index d878d72..1cf0534 100644
--- a/services/mediacodec/Android.mk
+++ b/services/mediacodec/Android.mk
@@ -70,7 +70,7 @@
LOCAL_MODULE := mediacodec.policy
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_REQUIRED_MODULES := crash_dump.policy
+LOCAL_REQUIRED_MODULES := crash_dump.policy code_coverage.policy
# mediacodec runs in 32-bit combatibility mode. For 64 bit architectures,
# use the 32 bit policy
ifdef TARGET_2ND_ARCH
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 3870a11..835f8bb 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -59,3 +59,5 @@
getrandom: 1
@include /system/etc/seccomp_policy/crash_dump.arm.policy
+
+@include /system/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediacodec/seccomp_policy/mediacodec-x86.policy b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
index d9c4045..a9d32d6 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-x86.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-x86.policy
@@ -69,3 +69,4 @@
gettid: 1
@include /system/etc/seccomp_policy/crash_dump.x86.policy
+@include /system/etc/seccomp_policy/code_coverage.x86.policy
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
index 9042cd7..93b4852 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm.policy
@@ -84,3 +84,5 @@
getgid32: 1
getegid32: 1
getgroups32: 1
+
+@include /system/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
index 4faf8b2..bb05770 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-arm64.policy
@@ -79,3 +79,4 @@
getegid: 1
getgroups: 1
+@include /system/etc/seccomp_policy/code_coverage.arm64.policy
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index 828e89a..816a6b1 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -68,6 +68,9 @@
src: "seccomp_policy/mediaextractor-x86_64.policy",
},
},
- required: ["crash_dump.policy"],
+ required: [
+ "crash_dump.policy",
+ "code_coverage.policy",
+ ],
}
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 964acf4..38f9be6 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -50,3 +50,4 @@
_llseek: 1
@include /system/etc/seccomp_policy/crash_dump.arm.policy
+@include /system/etc/seccomp_policy/code_coverage.arm.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index e6c676c..8fd8787 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -44,3 +44,4 @@
sched_yield: 1
@include /system/etc/seccomp_policy/crash_dump.arm64.policy
+@include /system/etc/seccomp_policy/code_coverage.arm64.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 56ad8df..05915d1 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -57,3 +57,4 @@
gettid: 1
@include /system/etc/seccomp_policy/crash_dump.x86.policy
+@include /system/etc/seccomp_policy/code_coverage.x86.policy
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
index 607a03e..e6a55d0 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86_64.policy
@@ -51,3 +51,4 @@
gettid: 1
@include /system/etc/seccomp_policy/crash_dump.x86_64.policy
+@include /system/etc/seccomp_policy/code_coverage.x86_64.policy