resolve merge conflicts of f7b975c56a98c3134adc5dc95834673eeee81f0d to qt-qpr1-dev-plus-aosp
Test: build
Test: Camera2 app take picture(sanity)
Merged-In: I4a697c1eaccc3603007be4a595febea981fbeb64
Change-Id: I8562c83478b1fe8fbda7c85f97b995985666918d
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index a5937fd..af8ec06 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -37,9 +37,11 @@
namespace.platform.isolated = true
-namespace.platform.search.paths = /system/${LIB}
+namespace.platform.search.paths = /system/${LIB}
+namespace.platform.search.paths += /apex/com.android.runtime/${LIB}
namespace.platform.asan.search.paths = /data/asan/system/${LIB}
namespace.platform.asan.search.paths += /system/${LIB}
+namespace.platform.asan.search.paths += /apex/com.android.runtime/${LIB}
# /system/lib/libc.so, etc are symlinks to /apex/com.android.lib/lib/bionic/libc.so, etc.
# Add /apex/... pat to the permitted paths because linker uses realpath(3)
diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
index 53b3d84..cef8ef5 100644
--- a/camera/cameraserver/main_cameraserver.cpp
+++ b/camera/cameraserver/main_cameraserver.cpp
@@ -34,6 +34,7 @@
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
CameraService::instantiate();
+ ALOGI("ServiceManager: %p done instantiate", sm.get());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 3328a85..9e034c4 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -138,6 +138,7 @@
private:
friend ACameraCaptureSession;
+ friend ACameraDevice;
camera_status_t checkCameraClosedOrErrorLocked() const;
@@ -387,7 +388,6 @@
mDevice(new android::acam::CameraDevice(id, cb, std::move(chars), this)) {}
~ACameraDevice();
-
/*******************
* NDK public APIs *
*******************/
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 37de30a..7ab0124 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -24,6 +24,7 @@
#include <algorithm>
#include <mutex>
#include <string>
+#include <variant>
#include <vector>
#include <stdio.h>
#include <stdio.h>
@@ -49,6 +50,7 @@
static constexpr int kTestImageFormat = AIMAGE_FORMAT_YUV_420_888;
using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
+using ConfiguredWindows = std::set<native_handle_t *>;
class CameraHelper {
public:
@@ -60,9 +62,12 @@
const char* physicalCameraId;
native_handle_t* anw;
};
- int initCamera(native_handle_t* imgReaderAnw,
+
+ // Retaining the error code in case the caller needs to analyze it.
+ std::variant<int, ConfiguredWindows> initCamera(native_handle_t* imgReaderAnw,
const std::vector<PhysicalImgReaderInfo>& physicalImgReaders,
bool usePhysicalSettings) {
+ ConfiguredWindows configuredWindows;
if (imgReaderAnw == nullptr) {
ALOGE("Cannot initialize camera before image reader get initialized.");
return -1;
@@ -78,7 +83,7 @@
ret = ACameraManager_openCamera(mCameraManager, mCameraId, &mDeviceCb, &mDevice);
if (ret != AMEDIA_OK || mDevice == nullptr) {
ALOGE("Failed to open camera, ret=%d, mDevice=%p.", ret, mDevice);
- return -1;
+ return ret;
}
// Create capture session
@@ -97,8 +102,9 @@
ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
return ret;
}
-
+ configuredWindows.insert(mImgReaderAnw);
std::vector<const char*> idPointerList;
+ std::set<const native_handle_t*> physicalStreamMap;
for (auto& physicalStream : physicalImgReaders) {
ACaptureSessionOutput* sessionOutput = nullptr;
ret = ACaptureSessionPhysicalOutput_create(physicalStream.anw,
@@ -112,21 +118,25 @@
ALOGE("ACaptureSessionOutputContainer_add failed, ret=%d", ret);
return ret;
}
- mExtraOutputs.push_back(sessionOutput);
+ ret = ACameraDevice_isSessionConfigurationSupported(mDevice, mOutputs);
+ if (ret != ACAMERA_OK && ret != ACAMERA_ERROR_UNSUPPORTED_OPERATION) {
+ ALOGW("ACameraDevice_isSessionConfigurationSupported failed, ret=%d camera id %s",
+ ret, mCameraId);
+ ACaptureSessionOutputContainer_remove(mOutputs, sessionOutput);
+ ACaptureSessionOutput_free(sessionOutput);
+ continue;
+ }
+ configuredWindows.insert(physicalStream.anw);
// Assume that at most one physical stream per physical camera.
mPhysicalCameraIds.push_back(physicalStream.physicalCameraId);
idPointerList.push_back(physicalStream.physicalCameraId);
+ physicalStreamMap.insert(physicalStream.anw);
+ mSessionPhysicalOutputs.push_back(sessionOutput);
}
ACameraIdList cameraIdList;
cameraIdList.numCameras = idPointerList.size();
cameraIdList.cameraIds = idPointerList.data();
- ret = ACameraDevice_isSessionConfigurationSupported(mDevice, mOutputs);
- if (ret != ACAMERA_OK && ret != ACAMERA_ERROR_UNSUPPORTED_OPERATION) {
- ALOGE("ACameraDevice_isSessionConfigurationSupported failed, ret=%d", ret);
- return ret;
- }
-
ret = ACameraDevice_createCaptureSession(mDevice, mOutputs, &mSessionCb, &mSession);
if (ret != AMEDIA_OK) {
ALOGE("ACameraDevice_createCaptureSession failed, ret=%d", ret);
@@ -157,6 +167,10 @@
}
for (auto& physicalStream : physicalImgReaders) {
+ if (physicalStreamMap.find(physicalStream.anw) == physicalStreamMap.end()) {
+ ALOGI("Skipping physicalStream anw=%p", physicalStream.anw);
+ continue;
+ }
ACameraOutputTarget* outputTarget = nullptr;
ret = ACameraOutputTarget_create(physicalStream.anw, &outputTarget);
if (ret != AMEDIA_OK) {
@@ -168,11 +182,11 @@
ALOGE("ACaptureRequest_addTarget failed, ret=%d", ret);
return ret;
}
- mReqExtraOutputs.push_back(outputTarget);
+ mReqPhysicalOutputs.push_back(outputTarget);
}
mIsCameraReady = true;
- return 0;
+ return configuredWindows;
}
@@ -184,10 +198,10 @@
ACameraOutputTarget_free(mReqImgReaderOutput);
mReqImgReaderOutput = nullptr;
}
- for (auto& outputTarget : mReqExtraOutputs) {
+ for (auto& outputTarget : mReqPhysicalOutputs) {
ACameraOutputTarget_free(outputTarget);
}
- mReqExtraOutputs.clear();
+ mReqPhysicalOutputs.clear();
if (mStillRequest) {
ACaptureRequest_free(mStillRequest);
mStillRequest = nullptr;
@@ -201,10 +215,10 @@
ACaptureSessionOutput_free(mImgReaderOutput);
mImgReaderOutput = nullptr;
}
- for (auto& extraOutput : mExtraOutputs) {
+ for (auto& extraOutput : mSessionPhysicalOutputs) {
ACaptureSessionOutput_free(extraOutput);
}
- mExtraOutputs.clear();
+ mSessionPhysicalOutputs.clear();
if (mOutputs) {
ACaptureSessionOutputContainer_free(mOutputs);
mOutputs = nullptr;
@@ -262,13 +276,13 @@
// Capture session
ACaptureSessionOutputContainer* mOutputs = nullptr;
ACaptureSessionOutput* mImgReaderOutput = nullptr;
- std::vector<ACaptureSessionOutput*> mExtraOutputs;
+ std::vector<ACaptureSessionOutput*> mSessionPhysicalOutputs;
ACameraCaptureSession* mSession = nullptr;
// Capture request
ACaptureRequest* mStillRequest = nullptr;
ACameraOutputTarget* mReqImgReaderOutput = nullptr;
- std::vector<ACameraOutputTarget*> mReqExtraOutputs;
+ std::vector<ACameraOutputTarget*> mReqPhysicalOutputs;
bool mIsCameraReady = false;
const char* mCameraId;
@@ -581,9 +595,11 @@
}
CameraHelper cameraHelper(id, mCameraManager);
- ret = cameraHelper.initCamera(testCase.getNativeWindow(),
- {}/*physicalImageReaders*/, false/*usePhysicalSettings*/);
- if (ret < 0) {
+ std::variant<int, ConfiguredWindows> retInit =
+ cameraHelper.initCamera(testCase.getNativeWindow(), {}/*physicalImageReaders*/,
+ false/*usePhysicalSettings*/);
+ int *retp = std::get_if<int>(&retInit);
+ if (retp) {
ALOGE("Unable to initialize camera helper");
return false;
}
@@ -751,10 +767,15 @@
physicalImgReaderInfo.push_back({physicalCameraIds[0], testCases[1]->getNativeWindow()});
physicalImgReaderInfo.push_back({physicalCameraIds[1], testCases[2]->getNativeWindow()});
- int ret = cameraHelper.initCamera(testCases[0]->getNativeWindow(),
- physicalImgReaderInfo, usePhysicalSettings);
- ASSERT_EQ(ret, 0);
-
+ std::variant<int, ConfiguredWindows> retInit =
+ cameraHelper.initCamera(testCases[0]->getNativeWindow(), physicalImgReaderInfo,
+ usePhysicalSettings);
+ int *retp = std::get_if<int>(&retInit);
+ ASSERT_EQ(retp, nullptr);
+ ConfiguredWindows *configuredWindowsp = std::get_if<ConfiguredWindows>(&retInit);
+ ASSERT_NE(configuredWindowsp, nullptr);
+ ASSERT_LE(configuredWindowsp->size(), testCases.size());
+ int ret = 0;
if (!cameraHelper.isCameraReady()) {
ALOGW("Camera is not ready after successful initialization. It's either due to camera "
"on board lacks BACKWARDS_COMPATIBLE capability or the device does not have "
@@ -776,9 +797,15 @@
break;
}
}
- ASSERT_EQ(testCases[0]->getAcquiredImageCount(), pictureCount);
- ASSERT_EQ(testCases[1]->getAcquiredImageCount(), pictureCount);
- ASSERT_EQ(testCases[2]->getAcquiredImageCount(), pictureCount);
+ for(auto &testCase : testCases) {
+ auto it = configuredWindowsp->find(testCase->getNativeWindow());
+ if (it == configuredWindowsp->end()) {
+ continue;
+ }
+ ALOGI("Testing window %p", testCase->getNativeWindow());
+ ASSERT_EQ(testCase->getAcquiredImageCount(), pictureCount);
+ }
+
ASSERT_TRUE(cameraHelper.checkCallbacks(pictureCount));
ACameraMetadata_free(staticMetadata);
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 185307e..defc94f 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -3,14 +3,15 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
stagefright.cpp \
jpeg.cpp \
SineSource.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libmedia libmedia_omx libutils libbinder \
+ libstagefright libmedia libmedia_codeclist libutils libbinder \
libstagefright_foundation libjpeg libui libgui libcutils liblog \
- libhidlbase \
+ libhidlbase libdatasource libaudioclient \
android.hardware.media.omx@1.0 \
LOCAL_C_INCLUDES:= \
@@ -31,12 +32,13 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
record.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libdatasource libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/camera/include \
@@ -57,12 +59,12 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- SineSource.cpp \
+ AudioPlayer.cpp \
recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -83,12 +85,13 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
+ AudioPlayer.cpp \
SineSource.cpp \
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
libstagefright libmedia liblog libutils libbinder \
- libstagefright_foundation
+ libstagefright_foundation libaudioclient
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -111,7 +114,7 @@
LOCAL_SHARED_LIBRARIES := \
libstagefright liblog libutils libbinder libui libgui \
- libstagefright_foundation libmedia libcutils
+ libstagefright_foundation libmedia libcutils libdatasource
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
diff --git a/media/libstagefright/AudioPlayer.cpp b/cmds/stagefright/AudioPlayer.cpp
similarity index 99%
rename from media/libstagefright/AudioPlayer.cpp
rename to cmds/stagefright/AudioPlayer.cpp
index 199b57b..208713d 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/cmds/stagefright/AudioPlayer.cpp
@@ -28,12 +28,13 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALookup.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include "AudioPlayer.h"
+
namespace android {
AudioPlayer::AudioPlayer(
diff --git a/media/libstagefright/include/media/stagefright/AudioPlayer.h b/cmds/stagefright/AudioPlayer.h
similarity index 100%
rename from media/libstagefright/include/media/stagefright/AudioPlayer.h
rename to cmds/stagefright/AudioPlayer.h
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index d4f2e8d..bd274d8 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -29,11 +29,11 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/AMRWriter.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/SimpleDecodingSource.h>
+#include "AudioPlayer.h"
#include "SineSource.h"
using namespace android;
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 95a16f3..37091c4 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,12 +17,11 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <datasource/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaCodecSource.h>
@@ -33,6 +32,8 @@
#include <media/stagefright/SimpleDecodingSource.h>
#include <media/MediaPlayerInterface.h>
+#include "AudioPlayer.h"
+
using namespace android;
static const int32_t kAudioBitRate = 12200;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index a63b9b9..01a178e 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include "SineSource.h"
-
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -25,8 +23,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaCodecSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index d55931c..a1ee904 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -31,6 +31,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
#include <media/MediaSource.h>
#include <media/IMediaHTTPService.h>
@@ -39,9 +40,6 @@
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include "include/NuCachedSource2.h"
-#include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaCodec.h>
@@ -68,6 +66,8 @@
#include <android/hardware/media/omx/1.0/IOmx.h>
+#include "AudioPlayer.h"
+
using namespace android;
static long gNumRepetitions;
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 35bdbc0..0634673 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -21,6 +21,7 @@
#include <binder/ProcessState.h>
#include <cutils/properties.h> // for property_get
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/IStreamSource.h>
@@ -28,7 +29,6 @@
#include <media/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MediaExtractor.h>
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp
index 919f4ee..e79fd4b 100644
--- a/drm/libmediadrm/DrmHal.cpp
+++ b/drm/libmediadrm/DrmHal.cpp
@@ -895,9 +895,8 @@
status_t DrmHal::provideKeyResponse(Vector<uint8_t> const &sessionId,
Vector<uint8_t> const &response, Vector<uint8_t> &keySetId) {
Mutex::Autolock autoLock(mLock);
- EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
-
INIT_CHECK();
+ EventTimer<status_t> keyResponseTimer(&mMetrics.mProvideKeyResponseTimeUs);
DrmSessionManager::Instance()->useSession(sessionId);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
index 23a35e5..f164f28 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/CryptoPlugin.cpp
@@ -62,10 +62,8 @@
secure, keyId, iv, mode, pattern, subSamples, source, offset, destination,
[&](Status_V1_2 hStatus, uint32_t hBytesWritten, hidl_string hDetailedError) {
status = toStatus_1_0(hStatus);
- if (status == Status::OK) {
- bytesWritten = hBytesWritten;
- detailedError = hDetailedError;
- }
+ bytesWritten = hBytesWritten;
+ detailedError = hDetailedError;
}
);
@@ -109,6 +107,10 @@
"destination decrypt buffer base not set");
return Void();
}
+ } else {
+ _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
+ "destination type not supported");
+ return Void();
}
sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
@@ -126,38 +128,45 @@
(static_cast<void *>(sourceBase->getPointer()));
uint8_t* srcPtr = static_cast<uint8_t *>(base + source.offset + offset);
void* destPtr = NULL;
- if (destination.type == BufferType::SHARED_MEMORY) {
- const SharedBuffer& destBuffer = destination.nonsecureMemory;
- sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
- if (destBase == nullptr) {
- _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
- return Void();
- }
-
- if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
- _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "invalid buffer size");
- return Void();
- }
- destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
- } else if (destination.type == BufferType::NATIVE_HANDLE) {
- native_handle_t *handle = const_cast<native_handle_t *>(
- destination.secureMemory.getNativeHandle());
- destPtr = static_cast<void *>(handle);
+ // destination.type == BufferType::SHARED_MEMORY
+ const SharedBuffer& destBuffer = destination.nonsecureMemory;
+ sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
+ if (destBase == nullptr) {
+ _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr");
+ return Void();
}
+ if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
+ _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "invalid buffer size");
+ return Void();
+ }
+ destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
+
+
// Calculate the output buffer size and determine if any subsamples are
// encrypted.
size_t destSize = 0;
bool haveEncryptedSubsamples = false;
for (size_t i = 0; i < subSamples.size(); i++) {
const SubSample &subSample = subSamples[i];
- destSize += subSample.numBytesOfClearData;
- destSize += subSample.numBytesOfEncryptedData;
+ if (__builtin_add_overflow(destSize, subSample.numBytesOfClearData, &destSize)) {
+ _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "subsample clear size overflow");
+ return Void();
+ }
+ if (__builtin_add_overflow(destSize, subSample.numBytesOfEncryptedData, &destSize)) {
+ _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "subsample encrypted size overflow");
+ return Void();
+ }
if (subSample.numBytesOfEncryptedData > 0) {
haveEncryptedSubsamples = true;
}
}
+ if (destSize > destBuffer.size) {
+ _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "subsample sum too large");
+ return Void();
+ }
+
if (mode == Mode::UNENCRYPTED) {
if (haveEncryptedSubsamples) {
_hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0,
diff --git a/include/media/AudioAttributes.h b/include/media/AudioAttributes.h
deleted file mode 120000
index 27ba471..0000000
--- a/include/media/AudioAttributes.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioAttributes.h
\ No newline at end of file
diff --git a/include/media/AudioCommonTypes.h b/include/media/AudioCommonTypes.h
deleted file mode 120000
index ae7c99a..0000000
--- a/include/media/AudioCommonTypes.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioCommonTypes.h
\ No newline at end of file
diff --git a/include/media/AudioIoDescriptor.h b/include/media/AudioIoDescriptor.h
deleted file mode 120000
index 68f54c9..0000000
--- a/include/media/AudioIoDescriptor.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioIoDescriptor.h
\ No newline at end of file
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
deleted file mode 120000
index a5889e5..0000000
--- a/include/media/AudioParameter.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioParameter.h
\ No newline at end of file
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
deleted file mode 120000
index dd4cd53..0000000
--- a/include/media/AudioPolicy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioPolicy.h
\ No newline at end of file
diff --git a/include/media/AudioProductStrategy.h b/include/media/AudioProductStrategy.h
deleted file mode 120000
index 6bfaf11..0000000
--- a/include/media/AudioProductStrategy.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioProductStrategy.h
\ No newline at end of file
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
deleted file mode 120000
index 9fad2b7..0000000
--- a/include/media/AudioSystem.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioSystem.h
\ No newline at end of file
diff --git a/include/media/AudioTimestamp.h b/include/media/AudioTimestamp.h
deleted file mode 120000
index b6b9278..0000000
--- a/include/media/AudioTimestamp.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioTimestamp.h
\ No newline at end of file
diff --git a/include/media/AudioVolumeGroup.h b/include/media/AudioVolumeGroup.h
deleted file mode 120000
index d6f1c99..0000000
--- a/include/media/AudioVolumeGroup.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/AudioVolumeGroup.h
\ No newline at end of file
diff --git a/include/media/IAudioFlingerClient.h b/include/media/IAudioFlingerClient.h
deleted file mode 120000
index dc481e8..0000000
--- a/include/media/IAudioFlingerClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioFlingerClient.h
\ No newline at end of file
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
deleted file mode 120000
index 0d4b3e7..0000000
--- a/include/media/IAudioPolicyServiceClient.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioPolicyServiceClient.h
\ No newline at end of file
diff --git a/media/bufferpool/1.0/AccessorImpl.cpp b/media/bufferpool/1.0/AccessorImpl.cpp
index fa17f15..a5366f6 100644
--- a/media/bufferpool/1.0/AccessorImpl.cpp
+++ b/media/bufferpool/1.0/AccessorImpl.cpp
@@ -151,6 +151,7 @@
newConnection->initialize(accessor, id);
*connection = newConnection;
*pConnectionId = id;
+ mBufferPool.mConnectionIds.insert(id);
++sSeqId;
}
}
@@ -305,7 +306,12 @@
found->second->mSenderValidated = true;
return true;
}
- // TODO: verify there is target connection Id
+ if (mConnectionIds.find(message.targetConnectionId) == mConnectionIds.end()) {
+ // N.B: it could be fake or receive connection already closed.
+ ALOGD("bufferpool %p receiver connection %lld is no longer valid",
+ this, (long long)message.targetConnectionId);
+ return false;
+ }
mStats.onBufferSent();
mTransactions.insert(std::make_pair(
message.transactionId,
@@ -450,6 +456,7 @@
}
}
}
+ mConnectionIds.erase(connectionId);
return true;
}
diff --git a/media/bufferpool/1.0/AccessorImpl.h b/media/bufferpool/1.0/AccessorImpl.h
index c04dbf3..84cb685 100644
--- a/media/bufferpool/1.0/AccessorImpl.h
+++ b/media/bufferpool/1.0/AccessorImpl.h
@@ -94,6 +94,7 @@
std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
std::set<BufferId> mFreeBuffers;
+ std::set<ConnectionId> mConnectionIds;
/// Buffer pool statistics which tracks allocation and transfer statistics.
struct Stats {
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index 94cf006..cacd465 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -163,6 +163,7 @@
*connection = newConnection;
*pConnectionId = id;
*pMsgId = mBufferPool.mInvalidation.mInvalidationId;
+ mBufferPool.mConnectionIds.insert(id);
mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
mBufferPool.mInvalidation.onConnect(id, observer);
++sSeqId;
@@ -474,7 +475,12 @@
found->second->mSenderValidated = true;
return true;
}
- // TODO: verify there is target connection Id
+ if (mConnectionIds.find(message.targetConnectionId) == mConnectionIds.end()) {
+ // N.B: it could be fake or receive connection already closed.
+ ALOGD("bufferpool2 %p receiver connection %lld is no longer valid",
+ this, (long long)message.targetConnectionId);
+ return false;
+ }
mStats.onBufferSent();
mTransactions.insert(std::make_pair(
message.transactionId,
@@ -644,6 +650,7 @@
}
}
}
+ mConnectionIds.erase(connectionId);
return true;
}
@@ -774,11 +781,19 @@
std::mutex &mutex,
std::condition_variable &cv,
bool &ready) {
+ constexpr uint32_t NUM_SPIN_TO_INCREASE_SLEEP = 1024;
+ constexpr uint32_t NUM_SPIN_TO_LOG = 1024*8;
+ constexpr useconds_t MAX_SLEEP_US = 10000;
+ uint32_t numSpin = 0;
+ useconds_t sleepUs = 1;
+
while(true) {
std::map<uint32_t, const std::weak_ptr<Accessor::Impl>> copied;
{
std::unique_lock<std::mutex> lock(mutex);
if (!ready) {
+ numSpin = 0;
+ sleepUs = 1;
cv.wait(lock);
}
copied.insert(accessors.begin(), accessors.end());
@@ -800,9 +815,20 @@
if (accessors.size() == 0) {
ready = false;
} else {
- // prevent draining cpu.
+ // TODO Use an efficient way to wait over FMQ.
+ // N.B. Since there is not a efficient way to wait over FMQ,
+ // polling over the FMQ is the current way to prevent draining
+ // CPU.
lock.unlock();
- std::this_thread::yield();
+ ++numSpin;
+ if (numSpin % NUM_SPIN_TO_INCREASE_SLEEP == 0 &&
+ sleepUs < MAX_SLEEP_US) {
+ sleepUs *= 10;
+ }
+ if (numSpin % NUM_SPIN_TO_LOG == 0) {
+ ALOGW("invalidator thread spinning");
+ }
+ ::usleep(sleepUs);
}
}
}
diff --git a/media/bufferpool/2.0/AccessorImpl.h b/media/bufferpool/2.0/AccessorImpl.h
index eea72b9..807e0f1 100644
--- a/media/bufferpool/2.0/AccessorImpl.h
+++ b/media/bufferpool/2.0/AccessorImpl.h
@@ -111,6 +111,7 @@
std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
std::set<BufferId> mFreeBuffers;
+ std::set<ConnectionId> mConnectionIds;
struct Invalidation {
static std::atomic<std::uint32_t> sInvSeqId;
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
index 4ae3b24..97f114a 100644
--- a/media/bufferpool/2.0/Android.bp
+++ b/media/bufferpool/2.0/Android.bp
@@ -1,9 +1,5 @@
-cc_library {
- name: "libstagefright_bufferpool@2.0",
- vendor_available: true,
- vndk: {
- enabled: true,
- },
+cc_defaults {
+ name: "libstagefright_bufferpool@2.0-default",
srcs: [
"Accessor.cpp",
"AccessorImpl.cpp",
@@ -29,3 +25,23 @@
"android.hardware.media.bufferpool@2.0",
],
}
+
+cc_library {
+ name: "libstagefright_bufferpool@2.0.1",
+ defaults: ["libstagefright_bufferpool@2.0-default"],
+ vendor_available: true,
+ cflags: [
+ "-DBUFFERPOOL_CLONE_HANDLES",
+ ],
+}
+
+// Deprecated. Do not use. Use libstagefright_bufferpool@2.0.1 instead.
+cc_library {
+ name: "libstagefright_bufferpool@2.0",
+ defaults: ["libstagefright_bufferpool@2.0-default"],
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+}
+
diff --git a/media/bufferpool/2.0/ClientManager.cpp b/media/bufferpool/2.0/ClientManager.cpp
index c31d313..87ee4e8 100644
--- a/media/bufferpool/2.0/ClientManager.cpp
+++ b/media/bufferpool/2.0/ClientManager.cpp
@@ -351,7 +351,21 @@
}
client = it->second;
}
+#ifdef BUFFERPOOL_CLONE_HANDLES
+ native_handle_t *origHandle;
+ ResultStatus res = client->allocate(params, &origHandle, buffer);
+ if (res != ResultStatus::OK) {
+ return res;
+ }
+ *handle = native_handle_clone(origHandle);
+ if (handle == NULL) {
+ buffer->reset();
+ return ResultStatus::NO_MEMORY;
+ }
+ return ResultStatus::OK;
+#else
return client->allocate(params, handle, buffer);
+#endif
}
ResultStatus ClientManager::Impl::receive(
@@ -367,7 +381,22 @@
}
client = it->second;
}
+#ifdef BUFFERPOOL_CLONE_HANDLES
+ native_handle_t *origHandle;
+ ResultStatus res = client->receive(
+ transactionId, bufferId, timestampUs, &origHandle, buffer);
+ if (res != ResultStatus::OK) {
+ return res;
+ }
+ *handle = native_handle_clone(origHandle);
+ if (handle == NULL) {
+ buffer->reset();
+ return ResultStatus::NO_MEMORY;
+ }
+ return ResultStatus::OK;
+#else
return client->receive(transactionId, bufferId, timestampUs, handle, buffer);
+#endif
}
ResultStatus ClientManager::Impl::postSend(
diff --git a/media/bufferpool/2.0/include/bufferpool/ClientManager.h b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
index 953c304..24b61f4 100644
--- a/media/bufferpool/2.0/include/bufferpool/ClientManager.h
+++ b/media/bufferpool/2.0/include/bufferpool/ClientManager.h
@@ -104,7 +104,9 @@
ResultStatus flush(ConnectionId connectionId);
/**
- * Allocates a buffer from the specified connection.
+ * Allocates a buffer from the specified connection. The output parameter
+ * handle is cloned from the internal handle. So it is safe to use directly,
+ * and it should be deleted and destroyed after use.
*
* @param connectionId The id of the connection.
* @param params The allocation parameters.
@@ -123,7 +125,9 @@
std::shared_ptr<BufferPoolData> *buffer);
/**
- * Receives a buffer for the transaction.
+ * Receives a buffer for the transaction. The output parameter handle is
+ * cloned from the internal handle. So it is safe to use directly, and it
+ * should be deleted and destoyed after use.
*
* @param connectionId The id of the receiving connection.
* @param transactionId The id for the transaction.
diff --git a/media/codec2/components/aac/C2SoftAacEnc.cpp b/media/codec2/components/aac/C2SoftAacEnc.cpp
index 8e3852c..1dc676b 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.cpp
+++ b/media/codec2/components/aac/C2SoftAacEnc.cpp
@@ -157,7 +157,7 @@
mSentCodecSpecificData(false),
mInputTimeSet(false),
mInputSize(0),
- mInputTimeUs(0),
+ mNextFrameTimestampUs(0),
mSignalledError(false),
mOutIndex(0u) {
}
@@ -183,7 +183,7 @@
mSentCodecSpecificData = false;
mInputTimeSet = false;
mInputSize = 0u;
- mInputTimeUs = 0;
+ mNextFrameTimestampUs = 0;
mSignalledError = false;
return C2_OK;
}
@@ -201,7 +201,7 @@
mSentCodecSpecificData = false;
mInputTimeSet = false;
mInputSize = 0u;
- mInputTimeUs = 0;
+ mNextFrameTimestampUs = 0;
return C2_OK;
}
@@ -365,17 +365,18 @@
capacity = view.capacity();
}
if (!mInputTimeSet && capacity > 0) {
- mInputTimeUs = work->input.ordinal.timestamp;
+ mNextFrameTimestampUs = work->input.ordinal.timestamp;
mInputTimeSet = true;
}
size_t numFrames = (capacity + mInputSize + (eos ? mNumBytesPerInputFrame - 1 : 0))
/ mNumBytesPerInputFrame;
- ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu mNumBytesPerInputFrame = %u",
- capacity, mInputSize, numFrames, mNumBytesPerInputFrame);
+ ALOGV("capacity = %zu; mInputSize = %zu; numFrames = %zu "
+ "mNumBytesPerInputFrame = %u inputTS = %lld",
+ capacity, mInputSize, numFrames,
+ mNumBytesPerInputFrame, work->input.ordinal.timestamp.peekll());
std::shared_ptr<C2LinearBlock> block;
- std::shared_ptr<C2Buffer> buffer;
std::unique_ptr<C2WriteView> wView;
uint8_t *outPtr = temp;
size_t outAvailable = 0u;
@@ -442,7 +443,11 @@
const std::shared_ptr<C2Buffer> mBuffer;
};
- C2WorkOrdinalStruct outOrdinal = work->input.ordinal;
+ struct OutputBuffer {
+ std::shared_ptr<C2Buffer> buffer;
+ c2_cntr64_t timestampUs;
+ };
+ std::list<OutputBuffer> outputBuffers;
while (encoderErr == AACENC_OK && inargs.numInSamples > 0) {
if (numFrames && !block) {
@@ -473,29 +478,22 @@
&outargs);
if (encoderErr == AACENC_OK) {
- if (buffer) {
- outOrdinal.frameIndex = mOutIndex++;
- outOrdinal.timestamp = mInputTimeUs;
- cloneAndSend(
- inputIndex,
- work,
- FillWork(C2FrameData::FLAG_INCOMPLETE, outOrdinal, buffer));
- buffer.reset();
- }
-
if (outargs.numOutBytes > 0) {
mInputSize = 0;
int consumed = (capacity / sizeof(int16_t)) - inargs.numInSamples
+ outargs.numInSamples;
- mInputTimeUs = work->input.ordinal.timestamp
+ c2_cntr64_t currentFrameTimestampUs = mNextFrameTimestampUs;
+ mNextFrameTimestampUs = work->input.ordinal.timestamp
+ (consumed * 1000000ll / channelCount / sampleRate);
- buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
+ std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, outargs.numOutBytes);
#if defined(LOG_NDEBUG) && !LOG_NDEBUG
hexdump(outPtr, std::min(outargs.numOutBytes, 256));
#endif
outPtr = temp;
outAvailable = 0;
block.reset();
+
+ outputBuffers.push_back({buffer, currentFrameTimestampUs});
} else {
mInputSize += outargs.numInSamples * sizeof(int16_t);
}
@@ -506,8 +504,9 @@
inargs.numInSamples -= outargs.numInSamples;
}
}
- ALOGV("encoderErr = %d mInputSize = %zu inargs.numInSamples = %d, mInputTimeUs = %lld",
- encoderErr, mInputSize, inargs.numInSamples, mInputTimeUs.peekll());
+ ALOGV("encoderErr = %d mInputSize = %zu "
+ "inargs.numInSamples = %d, mNextFrameTimestampUs = %lld",
+ encoderErr, mInputSize, inargs.numInSamples, mNextFrameTimestampUs.peekll());
}
if (eos && inBufferSize[0] > 0) {
@@ -542,10 +541,27 @@
&outargs);
}
- outOrdinal.frameIndex = mOutIndex++;
- outOrdinal.timestamp = mInputTimeUs;
+ while (outputBuffers.size() > 1) {
+ const OutputBuffer& front = outputBuffers.front();
+ C2WorkOrdinalStruct ordinal = work->input.ordinal;
+ ordinal.frameIndex = mOutIndex++;
+ ordinal.timestamp = front.timestampUs;
+ cloneAndSend(
+ inputIndex,
+ work,
+ FillWork(C2FrameData::FLAG_INCOMPLETE, ordinal, front.buffer));
+ outputBuffers.pop_front();
+ }
+ std::shared_ptr<C2Buffer> buffer;
+ C2WorkOrdinalStruct ordinal = work->input.ordinal;
+ ordinal.frameIndex = mOutIndex++;
+ if (!outputBuffers.empty()) {
+ ordinal.timestamp = outputBuffers.front().timestampUs;
+ buffer = outputBuffers.front().buffer;
+ }
+ // Mark the end of frame
FillWork((C2FrameData::flags_t)(eos ? C2FrameData::FLAG_END_OF_STREAM : 0),
- outOrdinal, buffer)(work);
+ ordinal, buffer)(work);
}
c2_status_t C2SoftAacEnc::drain(
@@ -569,7 +585,7 @@
mSentCodecSpecificData = false;
mInputTimeSet = false;
mInputSize = 0u;
- mInputTimeUs = 0;
+ mNextFrameTimestampUs = 0;
// 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 a38be19..2655039 100644
--- a/media/codec2/components/aac/C2SoftAacEnc.h
+++ b/media/codec2/components/aac/C2SoftAacEnc.h
@@ -56,7 +56,7 @@
bool mSentCodecSpecificData;
bool mInputTimeSet;
size_t mInputSize;
- c2_cntr64_t mInputTimeUs;
+ c2_cntr64_t mNextFrameTimestampUs;
bool mSignalledError;
std::atomic_uint64_t mOutIndex;
diff --git a/media/codec2/components/aom/Android.bp b/media/codec2/components/aom/Android.bp
index 0fabf5c..61dbd4c 100644
--- a/media/codec2/components/aom/Android.bp
+++ b/media/codec2/components/aom/Android.bp
@@ -1,10 +1,16 @@
cc_library_shared {
- name: "libcodec2_soft_av1dec",
+ name: "libcodec2_soft_av1dec_aom",
defaults: [
"libcodec2_soft-defaults",
"libcodec2_soft_sanitize_all-defaults",
],
+ // coordinated with frameworks/av/media/codec2/components/gav1/Android.bp
+ // so only 1 of them has the official c2.android.av1.decoder name
+ cflags: [
+ "-DCODECNAME=\"c2.android.av1-aom.decoder\"",
+ ],
+
srcs: ["C2SoftAomDec.cpp"],
static_libs: ["libaom"],
diff --git a/media/codec2/components/aom/C2SoftAomDec.cpp b/media/codec2/components/aom/C2SoftAomDec.cpp
index 769895c..36137e6 100644
--- a/media/codec2/components/aom/C2SoftAomDec.cpp
+++ b/media/codec2/components/aom/C2SoftAomDec.cpp
@@ -29,7 +29,8 @@
namespace android {
-constexpr char COMPONENT_NAME[] = "c2.android.av1.decoder";
+// codecname set and passed in as a compile flag from Android.bp
+constexpr char COMPONENT_NAME[] = CODECNAME;
class C2SoftAomDec::IntfImpl : public SimpleInterface<void>::BaseParams {
public:
@@ -340,6 +341,7 @@
aom_codec_flags_t flags;
memset(&flags, 0, sizeof(aom_codec_flags_t));
+ ALOGV("Using libaom AV1 software decoder.");
aom_codec_err_t err;
if ((err = aom_codec_dec_init(mCodecCtx, aom_codec_av1_dx(), &cfg, 0))) {
ALOGE("av1 decoder failed to initialize. (%d)", err);
diff --git a/media/codec2/components/avc/C2SoftAvcDec.cpp b/media/codec2/components/avc/C2SoftAvcDec.cpp
index 3f015b4..fa98178 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.cpp
+++ b/media/codec2/components/avc/C2SoftAvcDec.cpp
@@ -33,7 +33,8 @@
namespace {
constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder";
-
+constexpr uint32_t kDefaultOutputDelay = 8;
+constexpr uint32_t kMaxOutputDelay = 16;
} // namespace
class C2SoftAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -54,7 +55,9 @@
// TODO: Proper support for reorder depth.
addParameter(
DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
- .withConstValue(new C2PortActualDelayTuning::output(8u))
+ .withDefault(new C2PortActualDelayTuning::output(kDefaultOutputDelay))
+ .withFields({C2F(mActualOutputDelay, value).inRange(0, kMaxOutputDelay)})
+ .withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
.build());
// TODO: output latency and reordering
@@ -196,7 +199,6 @@
0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
.build());
}
-
static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
C2P<C2StreamPictureSizeInfo::output> &me) {
(void)mayBlock;
@@ -333,6 +335,7 @@
mDecHandle(nullptr),
mOutBufferFlush(nullptr),
mIvColorFormat(IV_YUV_420P),
+ mOutputDelay(kDefaultOutputDelay),
mWidth(320),
mHeight(240),
mHeaderDecoded(false),
@@ -882,6 +885,26 @@
work->result = C2_CORRUPTED;
return;
}
+ if (s_decode_op.i4_reorder_depth >= 0 && mOutputDelay != s_decode_op.i4_reorder_depth) {
+ mOutputDelay = s_decode_op.i4_reorder_depth;
+ ALOGV("New Output delay %d ", mOutputDelay);
+
+ C2PortActualDelayTuning::output outputDelay(mOutputDelay);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err =
+ mIntf->config({&outputDelay}, C2_MAY_BLOCK, &failures);
+ if (err == OK) {
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(outputDelay));
+ } else {
+ ALOGE("Cannot set output delay");
+ mSignalledError = true;
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
+ return;
+ }
+ continue;
+ }
if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
if (mHeaderDecoded == false) {
mHeaderDecoded = true;
diff --git a/media/codec2/components/avc/C2SoftAvcDec.h b/media/codec2/components/avc/C2SoftAvcDec.h
index 72ee583..4414a26 100644
--- a/media/codec2/components/avc/C2SoftAvcDec.h
+++ b/media/codec2/components/avc/C2SoftAvcDec.h
@@ -157,7 +157,7 @@
size_t mNumCores;
IV_COLOR_FORMAT_T mIvColorFormat;
-
+ uint32_t mOutputDelay;
uint32_t mWidth;
uint32_t mHeight;
uint32_t mStride;
diff --git a/media/codec2/components/cmds/Android.bp b/media/codec2/components/cmds/Android.bp
index 681a171..a081e28 100644
--- a/media/codec2/components/cmds/Android.bp
+++ b/media/codec2/components/cmds/Android.bp
@@ -17,6 +17,7 @@
"libbase",
"libbinder",
"libcutils",
+ "libdatasource",
"libgui",
"liblog",
"libstagefright",
diff --git a/media/codec2/components/cmds/codec2.cpp b/media/codec2/components/cmds/codec2.cpp
index 479f064..e572a53 100644
--- a/media/codec2/components/cmds/codec2.cpp
+++ b/media/codec2/components/cmds/codec2.cpp
@@ -30,6 +30,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
#include <mediadrm/ICrypto.h>
#include <media/IMediaHTTPService.h>
@@ -38,7 +39,6 @@
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractorFactory.h>
diff --git a/media/codec2/components/g711/C2SoftG711Dec.cpp b/media/codec2/components/g711/C2SoftG711Dec.cpp
index 43b843a..b6cc32e 100644
--- a/media/codec2/components/g711/C2SoftG711Dec.cpp
+++ b/media/codec2/components/g711/C2SoftG711Dec.cpp
@@ -73,7 +73,7 @@
addParameter(
DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
- .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
+ .withDefault(new C2StreamChannelCountInfo::output(0u, 6))
.withFields({C2F(mChannelCount, value).equalTo(1)})
.withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
.build());
diff --git a/media/codec2/components/gav1/Android.bp b/media/codec2/components/gav1/Android.bp
new file mode 100644
index 0000000..5c4abb7
--- /dev/null
+++ b/media/codec2/components/gav1/Android.bp
@@ -0,0 +1,20 @@
+cc_library_shared {
+ name: "libcodec2_soft_av1dec_gav1",
+ defaults: [
+ "libcodec2_soft-defaults",
+ "libcodec2_soft_sanitize_all-defaults",
+ ],
+
+ // coordinated with frameworks/av/media/codec2/components/aom/Android.bp
+ // so only 1 of them has the official c2.android.av1.decoder name
+ cflags: [
+ "-DCODECNAME=\"c2.android.av1.decoder\"",
+ ],
+
+ srcs: ["C2SoftGav1Dec.cpp"],
+ static_libs: ["libgav1"],
+
+ include_dirs: [
+ "external/libgav1/libgav1/",
+ ],
+}
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
new file mode 100644
index 0000000..ec5f549
--- /dev/null
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -0,0 +1,792 @@
+/*
+ * 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 "C2SoftGav1Dec"
+#include "C2SoftGav1Dec.h"
+
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+#include <SimpleC2Interface.h>
+#include <log/log.h>
+#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/MediaDefs.h>
+
+namespace android {
+
+// codecname set and passed in as a compile flag from Android.bp
+constexpr char COMPONENT_NAME[] = CODECNAME;
+
+class C2SoftGav1Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
+ public:
+ explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
+ : SimpleInterface<void>::BaseParams(
+ helper, COMPONENT_NAME, C2Component::KIND_DECODER,
+ C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AV1) {
+ noPrivateBuffers(); // TODO: account for our buffers here.
+ noInputReferences();
+ noOutputReferences();
+ noInputLatency();
+ noTimeStretch();
+
+ addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
+ .withConstValue(new C2ComponentAttributesSetting(
+ C2Component::ATTRIB_IS_TEMPORAL))
+ .build());
+
+ addParameter(
+ DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
+ .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
+ .withFields({
+ C2F(mSize, width).inRange(2, 2048, 2),
+ C2F(mSize, height).inRange(2, 2048, 2),
+ })
+ .withSetter(SizeSetter)
+ .build());
+
+ addParameter(DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
+ .withDefault(new C2StreamProfileLevelInfo::input(
+ 0u, C2Config::PROFILE_AV1_0, C2Config::LEVEL_AV1_2_1))
+ .withFields({C2F(mProfileLevel, profile)
+ .oneOf({C2Config::PROFILE_AV1_0,
+ C2Config::PROFILE_AV1_1}),
+ C2F(mProfileLevel, level)
+ .oneOf({
+ C2Config::LEVEL_AV1_2,
+ C2Config::LEVEL_AV1_2_1,
+ C2Config::LEVEL_AV1_2_2,
+ C2Config::LEVEL_AV1_3,
+ C2Config::LEVEL_AV1_3_1,
+ C2Config::LEVEL_AV1_3_2,
+ })})
+ .withSetter(ProfileLevelSetter, mSize)
+ .build());
+
+ mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
+ addParameter(
+ DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
+ .withDefault(mHdr10PlusInfoInput)
+ .withFields({
+ C2F(mHdr10PlusInfoInput, m.value).any(),
+ })
+ .withSetter(Hdr10PlusInfoInputSetter)
+ .build());
+
+ mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
+ addParameter(
+ DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
+ .withDefault(mHdr10PlusInfoOutput)
+ .withFields({
+ C2F(mHdr10PlusInfoOutput, m.value).any(),
+ })
+ .withSetter(Hdr10PlusInfoOutputSetter)
+ .build());
+
+ addParameter(
+ DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
+ .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
+ .withFields({
+ C2F(mSize, width).inRange(2, 2048, 2),
+ C2F(mSize, height).inRange(2, 2048, 2),
+ })
+ .withSetter(MaxPictureSizeSetter, mSize)
+ .build());
+
+ addParameter(DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
+ .withDefault(new C2StreamMaxBufferSizeInfo::input(
+ 0u, 320 * 240 * 3 / 4))
+ .withFields({
+ C2F(mMaxInputSize, value).any(),
+ })
+ .calculatedAs(MaxInputSizeSetter, mMaxSize)
+ .build());
+
+ C2ChromaOffsetStruct locations[1] = {C2ChromaOffsetStruct::ITU_YUV_420_0()};
+ std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
+ C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */,
+ C2Color::YUV_420);
+ memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
+
+ defaultColorInfo = C2StreamColorInfo::output::AllocShared(
+ {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */,
+ C2Color::YUV_420);
+ helper->addStructDescriptors<C2ChromaOffsetStruct>();
+
+ addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
+ .withConstValue(defaultColorInfo)
+ .build());
+
+ addParameter(
+ DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
+ .withDefault(new C2StreamColorAspectsTuning::output(
+ 0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
+ C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
+ .withFields(
+ {C2F(mDefaultColorAspects, range)
+ .inRange(C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
+ C2F(mDefaultColorAspects, primaries)
+ .inRange(C2Color::PRIMARIES_UNSPECIFIED,
+ C2Color::PRIMARIES_OTHER),
+ C2F(mDefaultColorAspects, transfer)
+ .inRange(C2Color::TRANSFER_UNSPECIFIED,
+ C2Color::TRANSFER_OTHER),
+ C2F(mDefaultColorAspects, matrix)
+ .inRange(C2Color::MATRIX_UNSPECIFIED,
+ C2Color::MATRIX_OTHER)})
+ .withSetter(DefaultColorAspectsSetter)
+ .build());
+
+ // TODO: support more formats?
+ addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
+ .withConstValue(new C2StreamPixelFormatInfo::output(
+ 0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
+ .build());
+ }
+
+ static C2R SizeSetter(bool mayBlock,
+ const C2P<C2StreamPictureSizeInfo::output> &oldMe,
+ C2P<C2StreamPictureSizeInfo::output> &me) {
+ (void)mayBlock;
+ C2R res = C2R::Ok();
+ if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
+ res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
+ me.set().width = oldMe.v.width;
+ }
+ if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
+ res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
+ me.set().height = oldMe.v.height;
+ }
+ return res;
+ }
+
+ static C2R MaxPictureSizeSetter(
+ bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
+ const C2P<C2StreamPictureSizeInfo::output> &size) {
+ (void)mayBlock;
+ // TODO: get max width/height from the size's field helpers vs.
+ // hardcoding
+ me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
+ me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
+ return C2R::Ok();
+ }
+
+ static C2R MaxInputSizeSetter(
+ bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
+ const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
+ (void)mayBlock;
+ // assume compression ratio of 2
+ me.set().value =
+ (((maxSize.v.width + 63) / 64) * ((maxSize.v.height + 63) / 64) * 3072);
+ return C2R::Ok();
+ }
+
+ static C2R DefaultColorAspectsSetter(
+ bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
+ (void)mayBlock;
+ if (me.v.range > C2Color::RANGE_OTHER) {
+ me.set().range = C2Color::RANGE_OTHER;
+ }
+ if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
+ me.set().primaries = C2Color::PRIMARIES_OTHER;
+ }
+ if (me.v.transfer > C2Color::TRANSFER_OTHER) {
+ me.set().transfer = C2Color::TRANSFER_OTHER;
+ }
+ if (me.v.matrix > C2Color::MATRIX_OTHER) {
+ me.set().matrix = C2Color::MATRIX_OTHER;
+ }
+ return C2R::Ok();
+ }
+
+ static C2R ProfileLevelSetter(
+ bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
+ const C2P<C2StreamPictureSizeInfo::output> &size) {
+ (void)mayBlock;
+ (void)size;
+ (void)me; // TODO: validate
+ return C2R::Ok();
+ }
+
+ std::shared_ptr<C2StreamColorAspectsTuning::output>
+ getDefaultColorAspects_l() {
+ return mDefaultColorAspects;
+ }
+
+ static C2R Hdr10PlusInfoInputSetter(bool mayBlock,
+ C2P<C2StreamHdr10PlusInfo::input> &me) {
+ (void)mayBlock;
+ (void)me; // TODO: validate
+ return C2R::Ok();
+ }
+
+ static C2R Hdr10PlusInfoOutputSetter(bool mayBlock,
+ C2P<C2StreamHdr10PlusInfo::output> &me) {
+ (void)mayBlock;
+ (void)me; // TODO: validate
+ return C2R::Ok();
+ }
+
+ private:
+ std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
+ std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
+ std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
+ std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
+ std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
+ std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
+ std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
+ std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
+ std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
+};
+
+C2SoftGav1Dec::C2SoftGav1Dec(const char *name, c2_node_id_t id,
+ const std::shared_ptr<IntfImpl> &intfImpl)
+ : SimpleC2Component(
+ std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
+ mIntf(intfImpl),
+ mCodecCtx(nullptr) {
+ gettimeofday(&mTimeStart, nullptr);
+ gettimeofday(&mTimeEnd, nullptr);
+}
+
+C2SoftGav1Dec::~C2SoftGav1Dec() { onRelease(); }
+
+c2_status_t C2SoftGav1Dec::onInit() {
+ return initDecoder() ? C2_OK : C2_CORRUPTED;
+}
+
+c2_status_t C2SoftGav1Dec::onStop() {
+ mSignalledError = false;
+ mSignalledOutputEos = false;
+ return C2_OK;
+}
+
+void C2SoftGav1Dec::onReset() {
+ (void)onStop();
+ c2_status_t err = onFlush_sm();
+ if (err != C2_OK) {
+ ALOGW("Failed to flush the av1 decoder. Trying to hard reset.");
+ destroyDecoder();
+ if (!initDecoder()) {
+ ALOGE("Hard reset failed.");
+ }
+ }
+}
+
+void C2SoftGav1Dec::onRelease() { destroyDecoder(); }
+
+c2_status_t C2SoftGav1Dec::onFlush_sm() {
+ Libgav1StatusCode status =
+ mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0,
+ /*user_private_data=*/0);
+ if (status != kLibgav1StatusOk) {
+ ALOGE("Failed to flush av1 decoder. status: %d.", status);
+ return C2_CORRUPTED;
+ }
+
+ // Dequeue frame (if any) that was enqueued previously.
+ const libgav1::DecoderBuffer *buffer;
+ status = mCodecCtx->DequeueFrame(&buffer);
+ if (status != kLibgav1StatusOk) {
+ ALOGE("Failed to dequeue frame after flushing the av1 decoder. status: %d",
+ status);
+ return C2_CORRUPTED;
+ }
+
+ mSignalledError = false;
+ mSignalledOutputEos = false;
+
+ return C2_OK;
+}
+
+static int GetCPUCoreCount() {
+ int cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+ cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+ // _SC_NPROC_ONLN must be defined...
+ cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+ CHECK(cpuCoreCount >= 1);
+ ALOGV("Number of CPU cores: %d", cpuCoreCount);
+ return cpuCoreCount;
+}
+
+bool C2SoftGav1Dec::initDecoder() {
+ mSignalledError = false;
+ mSignalledOutputEos = false;
+ mCodecCtx.reset(new libgav1::Decoder());
+
+ if (mCodecCtx == nullptr) {
+ ALOGE("mCodecCtx is null");
+ return false;
+ }
+
+ libgav1::DecoderSettings settings = {};
+ settings.threads = GetCPUCoreCount();
+
+ ALOGV("Using libgav1 AV1 software decoder.");
+ Libgav1StatusCode status = mCodecCtx->Init(&settings);
+ if (status != kLibgav1StatusOk) {
+ ALOGE("av1 decoder failed to initialize. status: %d.", status);
+ return false;
+ }
+
+ return true;
+}
+
+void C2SoftGav1Dec::destroyDecoder() { mCodecCtx = nullptr; }
+
+void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
+ uint32_t flags = 0;
+ if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
+ flags |= C2FrameData::FLAG_END_OF_STREAM;
+ ALOGV("signalling eos");
+ }
+ work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+ work->worklets.front()->output.buffers.clear();
+ work->worklets.front()->output.ordinal = work->input.ordinal;
+ work->workletsProcessed = 1u;
+}
+
+void C2SoftGav1Dec::finishWork(uint64_t index,
+ const std::unique_ptr<C2Work> &work,
+ const std::shared_ptr<C2GraphicBlock> &block) {
+ std::shared_ptr<C2Buffer> buffer =
+ createGraphicBuffer(block, C2Rect(mWidth, mHeight));
+ auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
+ uint32_t flags = 0;
+ if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
+ (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
+ flags |= C2FrameData::FLAG_END_OF_STREAM;
+ ALOGV("signalling eos");
+ }
+ work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
+ work->worklets.front()->output.buffers.clear();
+ work->worklets.front()->output.buffers.push_back(buffer);
+ work->worklets.front()->output.ordinal = work->input.ordinal;
+ work->workletsProcessed = 1u;
+ };
+ if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
+ fillWork(work);
+ } else {
+ finish(index, fillWork);
+ }
+}
+
+void C2SoftGav1Dec::process(const std::unique_ptr<C2Work> &work,
+ const std::shared_ptr<C2BlockPool> &pool) {
+ work->result = C2_OK;
+ work->workletsProcessed = 0u;
+ work->worklets.front()->output.configUpdate.clear();
+ work->worklets.front()->output.flags = work->input.flags;
+ if (mSignalledError || mSignalledOutputEos) {
+ work->result = C2_BAD_VALUE;
+ return;
+ }
+
+ size_t inOffset = 0u;
+ size_t inSize = 0u;
+ C2ReadView rView = mDummyReadView;
+ if (!work->input.buffers.empty()) {
+ rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
+ inSize = rView.capacity();
+ if (inSize && rView.error()) {
+ ALOGE("read view map failed %d", rView.error());
+ work->result = C2_CORRUPTED;
+ return;
+ }
+ }
+
+ bool codecConfig =
+ ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
+ bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
+
+ ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x", inSize,
+ (int)work->input.ordinal.timestamp.peeku(),
+ (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
+
+ if (codecConfig) {
+ fillEmptyWork(work);
+ return;
+ }
+
+ int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
+ if (inSize) {
+ uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
+ int32_t decodeTime = 0;
+ int32_t delay = 0;
+
+ GETTIME(&mTimeStart, nullptr);
+ TIME_DIFF(mTimeEnd, mTimeStart, delay);
+
+ const Libgav1StatusCode status =
+ mCodecCtx->EnqueueFrame(bitstream, inSize, frameIndex);
+
+ GETTIME(&mTimeEnd, nullptr);
+ TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
+ ALOGV("decodeTime=%4d delay=%4d\n", decodeTime, delay);
+
+ if (status != kLibgav1StatusOk) {
+ ALOGE("av1 decoder failed to decode frame. status: %d.", status);
+ work->result = C2_CORRUPTED;
+ work->workletsProcessed = 1u;
+ mSignalledError = true;
+ return;
+ }
+
+ } else {
+ const Libgav1StatusCode status =
+ mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0,
+ /*user_private_data=*/0);
+ if (status != kLibgav1StatusOk) {
+ ALOGE("Failed to flush av1 decoder. status: %d.", status);
+ work->result = C2_CORRUPTED;
+ work->workletsProcessed = 1u;
+ mSignalledError = true;
+ return;
+ }
+ }
+
+ (void)outputBuffer(pool, work);
+
+ if (eos) {
+ drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
+ mSignalledOutputEos = true;
+ } else if (!inSize) {
+ fillEmptyWork(work);
+ }
+}
+
+static void copyOutputBufferToYV12Frame(uint8_t *dst, const uint8_t *srcY,
+ const uint8_t *srcU,
+ const uint8_t *srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride,
+ uint32_t width, uint32_t height) {
+ const size_t dstYStride = align(width, 16);
+ const size_t dstUVStride = align(dstYStride / 2, 16);
+ uint8_t *const dstStart = dst;
+
+ for (size_t i = 0; i < height; ++i) {
+ memcpy(dst, srcY, width);
+ srcY += srcYStride;
+ dst += dstYStride;
+ }
+
+ dst = dstStart + dstYStride * height;
+ for (size_t i = 0; i < height / 2; ++i) {
+ memcpy(dst, srcV, width / 2);
+ srcV += srcVStride;
+ dst += dstUVStride;
+ }
+
+ dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
+ for (size_t i = 0; i < height / 2; ++i) {
+ memcpy(dst, srcU, width / 2);
+ srcU += srcUStride;
+ dst += dstUVStride;
+ }
+}
+
+static void convertYUV420Planar16ToY410(uint32_t *dst, const uint16_t *srcY,
+ const uint16_t *srcU,
+ const uint16_t *srcV, size_t srcYStride,
+ size_t srcUStride, size_t srcVStride,
+ size_t dstStride, size_t width,
+ size_t height) {
+ // Converting two lines at a time, slightly faster
+ for (size_t y = 0; y < height; y += 2) {
+ uint32_t *dstTop = (uint32_t *)dst;
+ uint32_t *dstBot = (uint32_t *)(dst + dstStride);
+ uint16_t *ySrcTop = (uint16_t *)srcY;
+ uint16_t *ySrcBot = (uint16_t *)(srcY + srcYStride);
+ uint16_t *uSrc = (uint16_t *)srcU;
+ uint16_t *vSrc = (uint16_t *)srcV;
+
+ uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
+ size_t x = 0;
+ for (; x < width - 3; x += 4) {
+ u01 = *((uint32_t *)uSrc);
+ uSrc += 2;
+ v01 = *((uint32_t *)vSrc);
+ vSrc += 2;
+
+ y01 = *((uint32_t *)ySrcTop);
+ ySrcTop += 2;
+ y23 = *((uint32_t *)ySrcTop);
+ ySrcTop += 2;
+ y45 = *((uint32_t *)ySrcBot);
+ ySrcBot += 2;
+ y67 = *((uint32_t *)ySrcBot);
+ ySrcBot += 2;
+
+ uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
+ uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
+
+ *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
+ *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
+ *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
+ *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
+
+ *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
+ *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
+ *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
+ *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
+ }
+
+ // There should be at most 2 more pixels to process. Note that we don't
+ // need to consider odd case as the buffer is always aligned to even.
+ if (x < width) {
+ u01 = *uSrc;
+ v01 = *vSrc;
+ y01 = *((uint32_t *)ySrcTop);
+ y45 = *((uint32_t *)ySrcBot);
+ uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
+ *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
+ *dstTop++ = ((y01 >> 16) << 10) | uv0;
+ *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
+ *dstBot++ = ((y45 >> 16) << 10) | uv0;
+ }
+
+ srcY += srcYStride * 2;
+ srcU += srcUStride;
+ srcV += srcVStride;
+ dst += dstStride * 2;
+ }
+}
+
+static void convertYUV420Planar16ToYUV420Planar(
+ uint8_t *dst, const uint16_t *srcY, const uint16_t *srcU,
+ const uint16_t *srcV, size_t srcYStride, size_t srcUStride,
+ size_t srcVStride, size_t dstStride, size_t width, size_t height) {
+ uint8_t *dstY = (uint8_t *)dst;
+ size_t dstYSize = dstStride * height;
+ size_t dstUVStride = align(dstStride / 2, 16);
+ size_t dstUVSize = dstUVStride * height / 2;
+ uint8_t *dstV = dstY + dstYSize;
+ uint8_t *dstU = dstV + dstUVSize;
+
+ for (size_t y = 0; y < height; ++y) {
+ for (size_t x = 0; x < width; ++x) {
+ dstY[x] = (uint8_t)(srcY[x] >> 2);
+ }
+
+ srcY += srcYStride;
+ dstY += dstStride;
+ }
+
+ for (size_t y = 0; y < (height + 1) / 2; ++y) {
+ for (size_t x = 0; x < (width + 1) / 2; ++x) {
+ dstU[x] = (uint8_t)(srcU[x] >> 2);
+ dstV[x] = (uint8_t)(srcV[x] >> 2);
+ }
+
+ srcU += srcUStride;
+ srcV += srcVStride;
+ dstU += dstUVStride;
+ dstV += dstUVStride;
+ }
+}
+
+bool C2SoftGav1Dec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool,
+ const std::unique_ptr<C2Work> &work) {
+ if (!(work && pool)) return false;
+
+ const libgav1::DecoderBuffer *buffer;
+ const Libgav1StatusCode status = mCodecCtx->DequeueFrame(&buffer);
+
+ if (status != kLibgav1StatusOk) {
+ ALOGE("av1 decoder DequeueFrame failed. status: %d.", status);
+ return false;
+ }
+
+ // |buffer| can be NULL if status was equal to kLibgav1StatusOk. This is not
+ // an error. This could mean one of two things:
+ // - The EnqueueFrame() call was either a flush (called with nullptr).
+ // - The enqueued frame did not have any displayable frames.
+ if (!buffer) {
+ return false;
+ }
+
+ const int width = buffer->displayed_width[0];
+ const int height = buffer->displayed_height[0];
+ if (width != mWidth || height != mHeight) {
+ mWidth = width;
+ mHeight = height;
+
+ C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+ if (err == C2_OK) {
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(size));
+ } else {
+ ALOGE("Config update size failed");
+ mSignalledError = true;
+ work->result = C2_CORRUPTED;
+ work->workletsProcessed = 1u;
+ return false;
+ }
+ }
+
+ // TODO(vigneshv): Add support for monochrome videos since AV1 supports it.
+ CHECK(buffer->image_format == libgav1::kImageFormatYuv420);
+
+ std::shared_ptr<C2GraphicBlock> block;
+ uint32_t format = HAL_PIXEL_FORMAT_YV12;
+ if (buffer->bitdepth == 10) {
+ IntfImpl::Lock lock = mIntf->lock();
+ std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects =
+ mIntf->getDefaultColorAspects_l();
+
+ if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
+ defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
+ defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
+ format = HAL_PIXEL_FORMAT_RGBA_1010102;
+ }
+ }
+ C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
+
+ c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format,
+ usage, &block);
+
+ if (err != C2_OK) {
+ ALOGE("fetchGraphicBlock for Output failed with status %d", err);
+ work->result = err;
+ return false;
+ }
+
+ C2GraphicView wView = block->map().get();
+
+ if (wView.error()) {
+ ALOGE("graphic view map failed %d", wView.error());
+ work->result = C2_CORRUPTED;
+ return false;
+ }
+
+ ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d", block->width(),
+ block->height(), mWidth, mHeight, (int)buffer->user_private_data);
+
+ uint8_t *dst = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
+ size_t srcYStride = buffer->stride[0];
+ size_t srcUStride = buffer->stride[1];
+ size_t srcVStride = buffer->stride[2];
+
+ if (buffer->bitdepth == 10) {
+ const uint16_t *srcY = (const uint16_t *)buffer->plane[0];
+ const uint16_t *srcU = (const uint16_t *)buffer->plane[1];
+ const uint16_t *srcV = (const uint16_t *)buffer->plane[2];
+
+ if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
+ convertYUV420Planar16ToY410(
+ (uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2, srcUStride / 2,
+ srcVStride / 2, align(mWidth, 16), mWidth, mHeight);
+ } else {
+ convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2,
+ srcUStride / 2, srcVStride / 2,
+ align(mWidth, 16), mWidth, mHeight);
+ }
+ } else {
+ const uint8_t *srcY = (const uint8_t *)buffer->plane[0];
+ const uint8_t *srcU = (const uint8_t *)buffer->plane[1];
+ const uint8_t *srcV = (const uint8_t *)buffer->plane[2];
+ copyOutputBufferToYV12Frame(dst, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, mWidth, mHeight);
+ }
+ finishWork(buffer->user_private_data, work, std::move(block));
+ block = nullptr;
+ return true;
+}
+
+c2_status_t C2SoftGav1Dec::drainInternal(
+ uint32_t drainMode, const std::shared_ptr<C2BlockPool> &pool,
+ const std::unique_ptr<C2Work> &work) {
+ if (drainMode == NO_DRAIN) {
+ ALOGW("drain with NO_DRAIN: no-op");
+ return C2_OK;
+ }
+ if (drainMode == DRAIN_CHAIN) {
+ ALOGW("DRAIN_CHAIN not supported");
+ return C2_OMITTED;
+ }
+
+ Libgav1StatusCode status =
+ mCodecCtx->EnqueueFrame(/*data=*/nullptr, /*size=*/0,
+ /*user_private_data=*/0);
+ if (status != kLibgav1StatusOk) {
+ ALOGE("Failed to flush av1 decoder. status: %d.", status);
+ return C2_CORRUPTED;
+ }
+
+ while (outputBuffer(pool, work)) {
+ }
+
+ if (drainMode == DRAIN_COMPONENT_WITH_EOS && work &&
+ work->workletsProcessed == 0u) {
+ fillEmptyWork(work);
+ }
+
+ return C2_OK;
+}
+
+c2_status_t C2SoftGav1Dec::drain(uint32_t drainMode,
+ const std::shared_ptr<C2BlockPool> &pool) {
+ return drainInternal(drainMode, pool, nullptr);
+}
+
+class C2SoftGav1Factory : public C2ComponentFactory {
+ public:
+ C2SoftGav1Factory()
+ : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
+ GetCodec2PlatformComponentStore()->getParamReflector())) {}
+
+ virtual c2_status_t createComponent(
+ c2_node_id_t id, std::shared_ptr<C2Component> *const component,
+ std::function<void(C2Component *)> deleter) override {
+ *component = std::shared_ptr<C2Component>(
+ new C2SoftGav1Dec(COMPONENT_NAME, id,
+ std::make_shared<C2SoftGav1Dec::IntfImpl>(mHelper)),
+ deleter);
+ return C2_OK;
+ }
+
+ virtual c2_status_t createInterface(
+ c2_node_id_t id, std::shared_ptr<C2ComponentInterface> *const interface,
+ std::function<void(C2ComponentInterface *)> deleter) override {
+ *interface = std::shared_ptr<C2ComponentInterface>(
+ new SimpleInterface<C2SoftGav1Dec::IntfImpl>(
+ COMPONENT_NAME, id,
+ std::make_shared<C2SoftGav1Dec::IntfImpl>(mHelper)),
+ deleter);
+ return C2_OK;
+ }
+
+ virtual ~C2SoftGav1Factory() override = default;
+
+ private:
+ std::shared_ptr<C2ReflectorHelper> mHelper;
+};
+
+} // namespace android
+
+extern "C" ::C2ComponentFactory *CreateCodec2Factory() {
+ ALOGV("in %s", __func__);
+ return new ::android::C2SoftGav1Factory();
+}
+
+extern "C" void DestroyCodec2Factory(::C2ComponentFactory *factory) {
+ ALOGV("in %s", __func__);
+ delete factory;
+}
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
new file mode 100644
index 0000000..a7c08bb
--- /dev/null
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -0,0 +1,77 @@
+/*
+ * 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_C2_SOFT_GAV1_DEC_H_
+#define ANDROID_C2_SOFT_GAV1_DEC_H_
+
+#include <SimpleC2Component.h>
+#include "libgav1/src/decoder.h"
+#include "libgav1/src/decoder_settings.h"
+
+#define GETTIME(a, b) gettimeofday(a, b);
+#define TIME_DIFF(start, end, diff) \
+ diff = (((end).tv_sec - (start).tv_sec) * 1000000) + \
+ ((end).tv_usec - (start).tv_usec);
+
+namespace android {
+
+struct C2SoftGav1Dec : public SimpleC2Component {
+ class IntfImpl;
+
+ C2SoftGav1Dec(const char* name, c2_node_id_t id,
+ const std::shared_ptr<IntfImpl>& intfImpl);
+ ~C2SoftGav1Dec();
+
+ // Begin SimpleC2Component overrides.
+ c2_status_t onInit() override;
+ c2_status_t onStop() override;
+ void onReset() override;
+ void onRelease() override;
+ c2_status_t onFlush_sm() override;
+ void process(const std::unique_ptr<C2Work>& work,
+ const std::shared_ptr<C2BlockPool>& pool) override;
+ c2_status_t drain(uint32_t drainMode,
+ const std::shared_ptr<C2BlockPool>& pool) override;
+ // End SimpleC2Component overrides.
+
+ private:
+ std::shared_ptr<IntfImpl> mIntf;
+ std::unique_ptr<libgav1::Decoder> mCodecCtx;
+
+ uint32_t mWidth;
+ uint32_t mHeight;
+ bool mSignalledOutputEos;
+ bool mSignalledError;
+
+ struct timeval mTimeStart; // Time at the start of decode()
+ struct timeval mTimeEnd; // Time at the end of decode()
+
+ bool initDecoder();
+ void destroyDecoder();
+ void finishWork(uint64_t index, const std::unique_ptr<C2Work>& work,
+ const std::shared_ptr<C2GraphicBlock>& block);
+ bool outputBuffer(const std::shared_ptr<C2BlockPool>& pool,
+ const std::unique_ptr<C2Work>& work);
+ c2_status_t drainInternal(uint32_t drainMode,
+ const std::shared_ptr<C2BlockPool>& pool,
+ const std::unique_ptr<C2Work>& work);
+
+ C2_DO_NOT_COPY(C2SoftGav1Dec);
+};
+
+} // namespace android
+
+#endif // ANDROID_C2_SOFT_GAV1_DEC_H_
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.cpp b/media/codec2/components/hevc/C2SoftHevcDec.cpp
index 7232572..df677c2 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcDec.cpp
@@ -33,7 +33,8 @@
namespace {
constexpr char COMPONENT_NAME[] = "c2.android.hevc.decoder";
-
+constexpr uint32_t kDefaultOutputDelay = 8;
+constexpr uint32_t kMaxOutputDelay = 16;
} // namespace
class C2SoftHevcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -54,7 +55,9 @@
// TODO: Proper support for reorder depth.
addParameter(
DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
- .withConstValue(new C2PortActualDelayTuning::output(8u))
+ .withDefault(new C2PortActualDelayTuning::output(kDefaultOutputDelay))
+ .withFields({C2F(mActualOutputDelay, value).inRange(0, kMaxOutputDelay)})
+ .withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
.build());
addParameter(
@@ -327,6 +330,7 @@
mDecHandle(nullptr),
mOutBufferFlush(nullptr),
mIvColorformat(IV_YUV_420P),
+ mOutputDelay(kDefaultOutputDelay),
mWidth(320),
mHeight(240),
mHeaderDecoded(false),
@@ -877,6 +881,26 @@
work->result = C2_CORRUPTED;
return;
}
+ if (s_decode_op.i4_reorder_depth >= 0 && mOutputDelay != s_decode_op.i4_reorder_depth) {
+ mOutputDelay = s_decode_op.i4_reorder_depth;
+ ALOGV("New Output delay %d ", mOutputDelay);
+
+ C2PortActualDelayTuning::output outputDelay(mOutputDelay);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err =
+ mIntf->config({&outputDelay}, C2_MAY_BLOCK, &failures);
+ if (err == OK) {
+ work->worklets.front()->output.configUpdate.push_back(
+ C2Param::Copy(outputDelay));
+ } else {
+ ALOGE("Cannot set output delay");
+ mSignalledError = true;
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
+ return;
+ }
+ continue;
+ }
if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
if (mHeaderDecoded == false) {
mHeaderDecoded = true;
diff --git a/media/codec2/components/hevc/C2SoftHevcDec.h b/media/codec2/components/hevc/C2SoftHevcDec.h
index b7664e6..ce63a6c 100644
--- a/media/codec2/components/hevc/C2SoftHevcDec.h
+++ b/media/codec2/components/hevc/C2SoftHevcDec.h
@@ -115,7 +115,7 @@
size_t mNumCores;
IV_COLOR_FORMAT_T mIvColorformat;
-
+ uint32_t mOutputDelay;
uint32_t mWidth;
uint32_t mHeight;
uint32_t mStride;
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index b129b1b..19ccbf9 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -42,6 +42,36 @@
constexpr char COMPONENT_NAME[] = "c2.android.hevc.encoder";
+void ParseGop(
+ const C2StreamGopTuning::output &gop,
+ uint32_t *syncInterval, uint32_t *iInterval, uint32_t *maxBframes) {
+ uint32_t syncInt = 1;
+ uint32_t iInt = 1;
+ for (size_t i = 0; i < gop.flexCount(); ++i) {
+ const C2GopLayerStruct &layer = gop.m.values[i];
+ if (layer.count == UINT32_MAX) {
+ syncInt = 0;
+ } else if (syncInt <= UINT32_MAX / (layer.count + 1)) {
+ syncInt *= (layer.count + 1);
+ }
+ if ((layer.type_ & I_FRAME) == 0) {
+ if (layer.count == UINT32_MAX) {
+ iInt = 0;
+ } else if (iInt <= UINT32_MAX / (layer.count + 1)) {
+ iInt *= (layer.count + 1);
+ }
+ }
+ if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME) && maxBframes) {
+ *maxBframes = layer.count;
+ }
+ }
+ if (syncInterval) {
+ *syncInterval = syncInt;
+ }
+ if (iInterval) {
+ *iInterval = iInt;
+ }
+}
} // namepsace
class C2SoftHevcEnc::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -60,13 +90,21 @@
setDerivedInstance(this);
addParameter(
+ DefineParam(mGop, C2_PARAMKEY_GOP)
+ .withDefault(C2StreamGopTuning::output::AllocShared(
+ 0 /* flexCount */, 0u /* stream */))
+ .withFields({C2F(mGop, m.values[0].type_).any(),
+ C2F(mGop, m.values[0].count).any()})
+ .withSetter(GopSetter)
+ .build());
+
+ addParameter(
DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY)
.withDefault(new C2PortActualDelayTuning::input(
DEFAULT_B_FRAMES + DEFAULT_RC_LOOKAHEAD))
.withFields({C2F(mActualInputDelay, value).inRange(
0, MAX_B_FRAMES + MAX_RC_LOOKAHEAD)})
- .withSetter(
- Setter<decltype(*mActualInputDelay)>::StrictValueWithNoDeps)
+ .calculatedAs(InputDelaySetter, mGop)
.build());
addParameter(
@@ -172,6 +210,17 @@
.build());
}
+ static C2R InputDelaySetter(
+ bool mayBlock,
+ C2P<C2PortActualDelayTuning::input> &me,
+ const C2P<C2StreamGopTuning::output> &gop) {
+ (void)mayBlock;
+ uint32_t maxBframes = 0;
+ ParseGop(gop.v, nullptr, nullptr, &maxBframes);
+ me.set().value = maxBframes + DEFAULT_RC_LOOKAHEAD;
+ return C2R::Ok();
+ }
+
static C2R BitrateSetter(bool mayBlock,
C2P<C2StreamBitrateInfo::output>& me) {
(void)mayBlock;
@@ -270,6 +319,18 @@
return C2R::Ok();
}
+ static C2R GopSetter(bool mayBlock, C2P<C2StreamGopTuning::output> &me) {
+ (void)mayBlock;
+ for (size_t i = 0; i < me.v.flexCount(); ++i) {
+ const C2GopLayerStruct &layer = me.v.m.values[0];
+ if (layer.type_ == C2Config::picture_type_t(P_FRAME | B_FRAME)
+ && layer.count > MAX_B_FRAMES) {
+ me.set().m.values[i].count = MAX_B_FRAMES;
+ }
+ }
+ return C2R::Ok();
+ }
+
UWORD32 getProfile_l() const {
switch (mProfileLevel->profile) {
case PROFILE_HEVC_MAIN: [[fallthrough]];
@@ -338,6 +399,9 @@
std::shared_ptr<C2StreamQualityTuning::output> getQuality_l() const {
return mQuality;
}
+ std::shared_ptr<C2StreamGopTuning::output> getGop_l() const {
+ return mGop;
+ }
private:
std::shared_ptr<C2StreamUsageTuning::input> mUsage;
@@ -350,6 +414,7 @@
std::shared_ptr<C2StreamQualityTuning::output> mQuality;
std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
+ std::shared_ptr<C2StreamGopTuning::output> mGop;
};
static size_t GetCPUCoreCount() {
@@ -449,7 +514,25 @@
ALOGE("HEVC default init failed : 0x%x", err);
return C2_CORRUPTED;
}
-
+ mBframes = 0;
+ if (mGop && mGop->flexCount() > 0) {
+ uint32_t syncInterval = 1;
+ uint32_t iInterval = 1;
+ uint32_t maxBframes = 0;
+ ParseGop(*mGop, &syncInterval, &iInterval, &maxBframes);
+ if (syncInterval > 0) {
+ ALOGD("Updating IDR interval from GOP: old %u new %u", mIDRInterval, syncInterval);
+ mIDRInterval = syncInterval;
+ }
+ if (iInterval > 0) {
+ ALOGD("Updating I interval from GOP: old %u new %u", mIInterval, iInterval);
+ mIInterval = iInterval;
+ }
+ if (mBframes != maxBframes) {
+ ALOGD("Updating max B frames from GOP: old %u new %u", mBframes, maxBframes);
+ mBframes = maxBframes;
+ }
+ }
// update configuration
mEncParams.s_src_prms.i4_width = mSize->width;
mEncParams.s_src_prms.i4_height = mSize->height;
@@ -463,12 +546,20 @@
mBitrate->value << 1;
mEncParams.s_tgt_lyr_prms.as_tgt_params[0].i4_codec_level = mHevcEncLevel;
mEncParams.s_coding_tools_prms.i4_max_i_open_gop_period = mIDRInterval;
- mEncParams.s_coding_tools_prms.i4_max_cra_open_gop_period = mIDRInterval;
+ mEncParams.s_coding_tools_prms.i4_max_cra_open_gop_period = mIInterval;
mIvVideoColorFormat = IV_YUV_420P;
mEncParams.s_multi_thrd_prms.i4_max_num_cores = mNumCores;
mEncParams.s_out_strm_prms.i4_codec_profile = mHevcEncProfile;
mEncParams.s_lap_prms.i4_rc_look_ahead_pics = DEFAULT_RC_LOOKAHEAD;
- mEncParams.s_coding_tools_prms.i4_max_temporal_layers = DEFAULT_B_FRAMES;
+ if (mBframes == 0) {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 0;
+ } else if (mBframes <= 2) {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 1;
+ } else if (mBframes <= 6) {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 2;
+ } else {
+ mEncParams.s_coding_tools_prms.i4_max_temporal_layers = 3;
+ }
switch (mBitrateMode->value) {
case C2Config::BITRATE_IGNORE:
@@ -523,6 +614,7 @@
c2_status_t C2SoftHevcEnc::initEncoder() {
CHECK(!mCodecCtx);
+
{
IntfImpl::Lock lock = mIntf->lock();
mSize = mIntf->getSize_l();
@@ -532,8 +624,10 @@
mHevcEncProfile = mIntf->getProfile_l();
mHevcEncLevel = mIntf->getLevel_l();
mIDRInterval = mIntf->getSyncFramePeriod_l();
+ mIInterval = mIntf->getSyncFramePeriod_l();
mComplexity = mIntf->getComplexity_l();
mQuality = mIntf->getQuality_l();
+ mGop = mIntf->getGop_l();
}
c2_status_t status = initEncParams();
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.h b/media/codec2/components/hevc/C2SoftHevcEnc.h
index f2c7642..140b4a9 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.h
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.h
@@ -67,6 +67,8 @@
ihevce_static_cfg_params_t mEncParams;
size_t mNumCores;
UWORD32 mIDRInterval;
+ UWORD32 mIInterval;
+ UWORD32 mBframes;
IV_COLOR_FORMAT_T mIvVideoColorFormat;
UWORD32 mHevcEncProfile;
UWORD32 mHevcEncLevel;
@@ -85,7 +87,7 @@
std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
std::shared_ptr<C2StreamComplexityTuning::output> mComplexity;
std::shared_ptr<C2StreamQualityTuning::output> mQuality;
-
+ std::shared_ptr<C2StreamGopTuning::output> mGop;
#ifdef FILE_DUMP_ENABLE
char mInFile[200];
char mOutFile[200];
diff --git a/media/codec2/hidl/1.0/utils/Android.bp b/media/codec2/hidl/1.0/utils/Android.bp
index 9db85d5..bdff29a 100644
--- a/media/codec2/hidl/1.0/utils/Android.bp
+++ b/media/codec2/hidl/1.0/utils/Android.bp
@@ -24,7 +24,7 @@
"libgui",
"libhidlbase",
"liblog",
- "libstagefright_bufferpool@2.0",
+ "libstagefright_bufferpool@2.0.1",
"libui",
"libutils",
],
@@ -37,7 +37,7 @@
"android.hardware.media.c2@1.0",
"libcodec2",
"libgui",
- "libstagefright_bufferpool@2.0",
+ "libstagefright_bufferpool@2.0.1",
"libui",
],
}
@@ -81,7 +81,7 @@
"libcutils",
"libhidlbase",
"liblog",
- "libstagefright_bufferpool@2.0",
+ "libstagefright_bufferpool@2.0.1",
"libstagefright_bufferqueue_helper",
"libui",
"libutils",
@@ -96,7 +96,7 @@
"libcodec2",
"libcodec2_vndk",
"libhidlbase",
- "libstagefright_bufferpool@2.0",
+ "libstagefright_bufferpool@2.0.1",
"libui",
],
}
diff --git a/media/codec2/hidl/1.0/utils/types.cpp b/media/codec2/hidl/1.0/utils/types.cpp
index 07dbf67..04fa59c 100644
--- a/media/codec2/hidl/1.0/utils/types.cpp
+++ b/media/codec2/hidl/1.0/utils/types.cpp
@@ -1434,6 +1434,11 @@
d->type = C2BaseBlock::GRAPHIC;
return true;
}
+ if (cHandle) {
+ // Though we got cloned handle, creating block failed.
+ native_handle_close(cHandle);
+ native_handle_delete(cHandle);
+ }
LOG(ERROR) << "Unknown handle type in BaseBlock::pooledBlock.";
return false;
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 6469735..a8a552c 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,6 +547,10 @@
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/hidl/1.0/vts/functional/common/README.md b/media/codec2/hidl/1.0/vts/functional/common/README.md
index 50e8356..f2f579c 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/README.md
+++ b/media/codec2/hidl/1.0/vts/functional/common/README.md
@@ -1,31 +1,36 @@
-## Codec2 VTS Hal @ 1.0 tests ##
----
-#### master :
+# Codec2 VTS Hal @ 1.0 tests #
+
+## master :
Functionality of master is to enumerate all the Codec2 components available in C2 media service.
-usage: VtsHalMediaC2V1\_0TargetMasterTest -I default
+usage: `VtsHalMediaC2V1_0TargetMasterTest -I default`
-#### component :
+## component :
Functionality of component test is to validate common functionality across all the Codec2 components available in C2 media service. For a standard C2 component, these tests are expected to pass.
-usage: VtsHalMediaC2V1\_0TargetComponentTest -I software -C <comp name>
-example: VtsHalMediaC2V1\_0TargetComponentTest -I software -C c2.android.vorbis.decoder
+usage: `VtsHalMediaC2V1_0TargetComponentTest -I software -C <comp name>`
-#### audio :
-Functionality of audio test is to validate audio specific functionality Codec2 components. The resource files for this test are taken from media/codec2/hidl/1.0/vts/functional/res. The path to these files on the device is required to be given for bitstream tests.
+example: `VtsHalMediaC2V1_0TargetComponentTest -I software -C c2.android.vorbis.decoder`
-usage: VtsHalMediaC2V1\_0TargetAudioDecTest -I default -C <comp name> -P /sdcard/media/
-usage: VtsHalMediaC2V1\_0TargetAudioEncTest -I software -C <comp name> -P /sdcard/media/
+## audio :
+Functionality of audio test is to validate audio specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.)
-example: VtsHalMediaC2V1\_0TargetAudioDecTest -I software -C c2.android.flac.decoder -P /sdcard/media/
-example: VtsHalMediaC2V1\_0TargetAudioEncTest -I software -C c2.android.opus.encoder -P /sdcard/media/
+usage: `VtsHalMediaC2V1_0TargetAudioDecTest -I default -C <comp name> -P <path to resource files>`
-#### video :
-Functionality of video test is to validate video specific functionality Codec2 components. The resource files for this test are taken from media/codec2/hidl/1.0/vts/functional/res. The path to these files on the device is required to be given for bitstream tests.
+usage: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C <comp name> -P <path to resource files>`
-usage: VtsHalMediaC2V1\_0TargetVideoDecTest -I default -C <comp name> -P /sdcard/media/
-usage: VtsHalMediaC2V1\_0TargetVideoEncTest -I software -C <comp name> -P /sdcard/media/
+example: `VtsHalMediaC2V1_0TargetAudioDecTest -I software -C c2.android.flac.decoder -P /data/local/tmp/media/`
-example: VtsHalMediaC2V1\_0TargetVideoDecTest -I software -C c2.android.avc.decoder -P /sdcard/media/
-example: VtsHalMediaC2V1\_0TargetVideoEncTest -I software -C c2.android.vp9.encoder -P /sdcard/media/
+example: `VtsHalMediaC2V1_0TargetAudioEncTest -I software -C c2.android.opus.encoder -P /data/local/tmp/media/`
+
+## video :
+Functionality of video test is to validate video specific functionality of Codec2 components. The resource files for this test are taken from `frameworks/av/media/codec2/hidl/1.0/vts/functional/res`. The path to these files on the device can be specified with `-P`. (If the device path is omitted, `/data/local/tmp/media/` is the default value.)
+
+usage: `VtsHalMediaC2V1_0TargetVideoDecTest -I default -C <comp name> -P <path to resource files>`
+
+usage: `VtsHalMediaC2V1_0TargetVideoEncTest -I software -C <comp name> -P <path to resource files>`
+
+example: `VtsHalMediaC2V1_0TargetVideoDecTest -I software -C c2.android.avc.decoder -P /data/local/tmp/media/`
+
+example: `VtsHalMediaC2V1_0TargetVideoEncTest -I software -C c2.android.vp9.encoder -P /data/local/tmp/media/`
diff --git a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index c577dac..db59e54 100644
--- a/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -118,7 +118,7 @@
registerTestService<IComponentStore>();
}
- ComponentTestEnvironment() : res("/sdcard/media/") {}
+ ComponentTestEnvironment() : res("/data/local/tmp/media/") {}
void setComponent(const char* _component) { component = _component; }
diff --git a/media/codec2/hidl/client/Android.bp b/media/codec2/hidl/client/Android.bp
index 672369c..89c1c4a 100644
--- a/media/codec2/hidl/client/Android.bp
+++ b/media/codec2/hidl/client/Android.bp
@@ -18,7 +18,7 @@
"libgui",
"libhidlbase",
"liblog",
- "libstagefright_bufferpool@2.0",
+ "libstagefright_bufferpool@2.0.1",
"libui",
"libutils",
],
diff --git a/media/codec2/hidl/client/client.cpp b/media/codec2/hidl/client/client.cpp
index 5ed54f1..c620bad 100644
--- a/media/codec2/hidl/client/client.cpp
+++ b/media/codec2/hidl/client/client.cpp
@@ -883,66 +883,72 @@
Codec2Client::CreateComponentByName(
const char* componentName,
const std::shared_ptr<Listener>& listener,
- std::shared_ptr<Codec2Client>* owner) {
- std::shared_ptr<Component> component;
- c2_status_t status = ForAllServices(
- componentName,
- [owner, &component, componentName, &listener](
- const std::shared_ptr<Codec2Client> &client)
- -> c2_status_t {
- c2_status_t status = client->createComponent(componentName,
- listener,
- &component);
- if (status == C2_OK) {
- if (owner) {
- *owner = client;
+ std::shared_ptr<Codec2Client>* owner,
+ size_t numberOfAttempts) {
+ while (true) {
+ std::shared_ptr<Component> component;
+ c2_status_t status = ForAllServices(
+ componentName,
+ [owner, &component, componentName, &listener](
+ const std::shared_ptr<Codec2Client> &client)
+ -> c2_status_t {
+ c2_status_t status = client->createComponent(componentName,
+ listener,
+ &component);
+ if (status == C2_OK) {
+ if (owner) {
+ *owner = client;
+ }
+ } else if (status != C2_NOT_FOUND) {
+ LOG(DEBUG) << "IComponentStore("
+ << client->getServiceName()
+ << ")::createComponent(\"" << componentName
+ << "\") returned status = "
+ << status << ".";
}
- } else if (status != C2_NOT_FOUND) {
- LOG(DEBUG) << "IComponentStore("
- << client->getServiceName()
- << ")::createComponent(\"" << componentName
- << "\") returned status = "
- << status << ".";
- }
- return status;
- });
- if (status != C2_OK) {
- LOG(DEBUG) << "Could not create component \"" << componentName << "\". "
- "Status = " << status << ".";
+ return status;
+ });
+ if (numberOfAttempts > 0 && status == C2_TRANSACTION_FAILED) {
+ --numberOfAttempts;
+ continue;
+ }
+ return component;
}
- return component;
}
std::shared_ptr<Codec2Client::Interface>
Codec2Client::CreateInterfaceByName(
const char* interfaceName,
- std::shared_ptr<Codec2Client>* owner) {
- std::shared_ptr<Interface> interface;
- c2_status_t status = ForAllServices(
- interfaceName,
- [owner, &interface, interfaceName](
- const std::shared_ptr<Codec2Client> &client)
- -> c2_status_t {
- c2_status_t status = client->createInterface(interfaceName,
- &interface);
- if (status == C2_OK) {
- if (owner) {
- *owner = client;
+ std::shared_ptr<Codec2Client>* owner,
+ size_t numberOfAttempts) {
+ while (true) {
+ std::shared_ptr<Interface> interface;
+ c2_status_t status = ForAllServices(
+ interfaceName,
+ [owner, &interface, interfaceName](
+ const std::shared_ptr<Codec2Client> &client)
+ -> c2_status_t {
+ c2_status_t status = client->createInterface(interfaceName,
+ &interface);
+ if (status == C2_OK) {
+ if (owner) {
+ *owner = client;
+ }
+ } else if (status != C2_NOT_FOUND) {
+ LOG(DEBUG) << "IComponentStore("
+ << client->getServiceName()
+ << ")::createInterface(\"" << interfaceName
+ << "\") returned status = "
+ << status << ".";
}
- } else if (status != C2_NOT_FOUND) {
- LOG(DEBUG) << "IComponentStore("
- << client->getServiceName()
- << ")::createInterface(\"" << interfaceName
- << "\") returned status = "
- << status << ".";
- }
- return status;
- });
- if (status != C2_OK) {
- LOG(DEBUG) << "Could not create interface \"" << interfaceName << "\". "
- "Status = " << status << ".";
+ return status;
+ });
+ if (numberOfAttempts > 0 && status == C2_TRANSACTION_FAILED) {
+ --numberOfAttempts;
+ continue;
+ }
+ return interface;
}
- return interface;
}
std::vector<C2Component::Traits> const& Codec2Client::ListComponents() {
diff --git a/media/codec2/hidl/client/include/codec2/hidl/client.h b/media/codec2/hidl/client/include/codec2/hidl/client.h
index b8a7fb5..848901d 100644
--- a/media/codec2/hidl/client/include/codec2/hidl/client.h
+++ b/media/codec2/hidl/client/include/codec2/hidl/client.h
@@ -179,17 +179,21 @@
static std::vector<std::shared_ptr<Codec2Client>> CreateFromAllServices();
// Try to create a component with a given name from all known
- // IComponentStore services.
+ // IComponentStore services. numberOfAttempts determines the number of times
+ // to retry the HIDL call if the transaction fails.
static std::shared_ptr<Component> CreateComponentByName(
char const* componentName,
std::shared_ptr<Listener> const& listener,
- std::shared_ptr<Codec2Client>* owner = nullptr);
+ std::shared_ptr<Codec2Client>* owner = nullptr,
+ size_t numberOfAttempts = 10);
// Try to create a component interface with a given name from all known
- // IComponentStore services.
+ // IComponentStore services. numberOfAttempts determines the number of times
+ // to retry the HIDL call if the transaction fails.
static std::shared_ptr<Interface> CreateInterfaceByName(
char const* interfaceName,
- std::shared_ptr<Codec2Client>* owner = nullptr);
+ std::shared_ptr<Codec2Client>* owner = nullptr,
+ size_t numberOfAttempts = 10);
// List traits from all known IComponentStore services.
static std::vector<C2Component::Traits> const& ListComponents();
diff --git a/media/codec2/sfplugin/Android.bp b/media/codec2/sfplugin/Android.bp
index 5112e80..ec576c9 100644
--- a/media/codec2/sfplugin/Android.bp
+++ b/media/codec2/sfplugin/Android.bp
@@ -23,6 +23,7 @@
header_libs: [
"libcodec2_internal",
"libmediadrm_headers",
+ "media_ndk_headers",
],
shared_libs: [
@@ -40,7 +41,7 @@
"libhidlallocatorutils",
"libhidlbase",
"liblog",
- "libmedia",
+ "libmedia_codeclist",
"libmedia_omx",
"libsfplugin_ccodec_utils",
"libstagefright_bufferqueue_helper",
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 9d1cc60..4a31953 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -375,7 +375,11 @@
// consumer usage is queried earlier.
- ALOGD("ISConfig%s", status.str().c_str());
+ if (status.str().empty()) {
+ ALOGD("ISConfig not changed");
+ } else {
+ ALOGD("ISConfig%s", status.str().c_str());
+ }
return err;
}
@@ -810,9 +814,17 @@
}
{
- double value;
- if (msg->findDouble("time-lapse-fps", &value)) {
- config->mISConfig->mCaptureFps = value;
+ bool captureFpsFound = false;
+ double timeLapseFps;
+ float captureRate;
+ if (msg->findDouble("time-lapse-fps", &timeLapseFps)) {
+ config->mISConfig->mCaptureFps = timeLapseFps;
+ captureFpsFound = true;
+ } else if (msg->findAsFloat(KEY_CAPTURE_RATE, &captureRate)) {
+ config->mISConfig->mCaptureFps = captureRate;
+ captureFpsFound = true;
+ }
+ if (captureFpsFound) {
(void)msg->findAsFloat(KEY_FRAME_RATE, &config->mISConfig->mCodedFps);
}
}
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 8308292..2efb987 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -948,7 +948,11 @@
uint32_t outputGeneration;
{
Mutexed<OutputSurface>::Locked output(mOutputSurface);
- output->maxDequeueBuffers = numOutputSlots + reorderDepth.value + kRenderingDepth;
+ output->maxDequeueBuffers = numOutputSlots +
+ reorderDepth.value + kRenderingDepth;
+ if (!secure) {
+ output->maxDequeueBuffers += numInputSlots;
+ }
outputSurface = output->surface ?
output->surface->getIGraphicBufferProducer() : nullptr;
if (outputSurface) {
@@ -1328,13 +1332,18 @@
case C2PortReorderBufferDepthTuning::CORE_INDEX: {
C2PortReorderBufferDepthTuning::output reorderDepth;
if (reorderDepth.updateFrom(*param)) {
+ bool secure = mComponent->getName().find(".secure") != std::string::npos;
mReorderStash.lock()->setDepth(reorderDepth.value);
ALOGV("[%s] onWorkDone: updated reorder depth to %u",
mName, reorderDepth.value);
size_t numOutputSlots = mOutput.lock()->numSlots;
+ size_t numInputSlots = mInput.lock()->numSlots;
Mutexed<OutputSurface>::Locked output(mOutputSurface);
- output->maxDequeueBuffers =
- numOutputSlots + reorderDepth.value + kRenderingDepth;
+ output->maxDequeueBuffers = numOutputSlots +
+ reorderDepth.value + kRenderingDepth;
+ if (!secure) {
+ output->maxDequeueBuffers += numInputSlots;
+ }
if (output->surface) {
output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
}
@@ -1378,10 +1387,12 @@
if (outputDelay.updateFrom(*param)) {
ALOGV("[%s] onWorkDone: updating output delay %u",
mName, outputDelay.value);
+ bool secure = mComponent->getName().find(".secure") != std::string::npos;
(void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
bool outputBuffersChanged = false;
size_t numOutputSlots = 0;
+ size_t numInputSlots = mInput.lock()->numSlots;
{
Mutexed<Output>::Locked output(mOutput);
output->outputDelay = outputDelay.value;
@@ -1407,6 +1418,9 @@
uint32_t depth = mReorderStash.lock()->depth();
Mutexed<OutputSurface>::Locked output(mOutputSurface);
output->maxDequeueBuffers = numOutputSlots + depth + kRenderingDepth;
+ if (!secure) {
+ output->maxDequeueBuffers += numInputSlots;
+ }
if (output->surface) {
output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
}
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 26c702d..ed8b832 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -878,9 +878,10 @@
switch (c2buffer->data().type()) {
case C2BufferData::LINEAR: {
uint32_t size = kLinearBufferSize;
- const C2ConstLinearBlock &block = c2buffer->data().linearBlocks().front();
- if (block.size() < kMaxLinearBufferSize / 2) {
- size = block.size() * 2;
+ const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
+ const uint32_t block_size = linear_blocks.front().size();
+ if (block_size < kMaxLinearBufferSize / 2) {
+ size = block_size * 2;
} else {
size = kMaxLinearBufferSize;
}
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index 1cfdc19..5adcd94 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -235,7 +235,10 @@
const std::vector<ConfigMapper> &getConfigMappersForSdkKey(std::string key) const {
auto it = mConfigMappers.find(key);
if (it == mConfigMappers.end()) {
- ALOGD("no c2 equivalents for %s", key.c_str());
+ if (mComplained.count(key) == 0) {
+ ALOGD("no c2 equivalents for %s", key.c_str());
+ mComplained.insert(key);
+ }
return NO_MAPPERS;
}
ALOGV("found %zu eqs for %s", it->second.size(), key.c_str());
@@ -304,6 +307,7 @@
private:
std::map<SdkKey, std::vector<ConfigMapper>> mConfigMappers;
+ mutable std::set<std::string> mComplained;
};
const std::vector<ConfigMapper> StandardParams::NO_MAPPERS;
@@ -508,7 +512,8 @@
.limitTo(D::ENCODER & D::VIDEO));
// convert to timestamp base
add(ConfigMapper(KEY_I_FRAME_INTERVAL, C2_PARAMKEY_SYNC_FRAME_INTERVAL, "value")
- .withMappers([](C2Value v) -> C2Value {
+ .limitTo(D::VIDEO & D::ENCODER & D::CONFIG)
+ .withMapper([](C2Value v) -> C2Value {
// convert from i32 to float
int32_t i32Value;
float fpValue;
@@ -518,12 +523,6 @@
return int64_t(c2_min(1000000 * fpValue + 0.5, (double)INT64_MAX));
}
return C2Value();
- }, [](C2Value v) -> C2Value {
- int64_t i64;
- if (v.get(&i64)) {
- return float(i64) / 1000000;
- }
- return C2Value();
}));
// remove when codecs switch to proper coding.gop (add support for calculating gop)
deprecated(ConfigMapper("i-frame-period", "coding.gop", "intra-period")
@@ -1033,7 +1032,25 @@
}
ReflectedParamUpdater::Dict reflected = mParamUpdater->getParams(paramPointers);
- ALOGD("c2 config is %s", reflected.debugString().c_str());
+ std::string config = reflected.debugString();
+ std::set<std::string> configLines;
+ std::string diff;
+ for (size_t start = 0; start != std::string::npos; ) {
+ size_t end = config.find('\n', start);
+ size_t count = (end == std::string::npos)
+ ? std::string::npos
+ : end - start + 1;
+ std::string line = config.substr(start, count);
+ configLines.insert(line);
+ if (mLastConfig.count(line) == 0) {
+ diff.append(line);
+ }
+ start = (end == std::string::npos) ? std::string::npos : end + 1;
+ }
+ if (!diff.empty()) {
+ ALOGD("c2 config diff is %s", diff.c_str());
+ }
+ mLastConfig.swap(configLines);
bool changed = false;
if (domain & mInputDomain) {
diff --git a/media/codec2/sfplugin/CCodecConfig.h b/media/codec2/sfplugin/CCodecConfig.h
index 3bafe3f..a61c8b7 100644
--- a/media/codec2/sfplugin/CCodecConfig.h
+++ b/media/codec2/sfplugin/CCodecConfig.h
@@ -134,6 +134,8 @@
/// For now support a validation function.
std::map<C2Param::Index, LocalParamValidator> mLocalParams;
+ std::set<std::string> mLastConfig;
+
CCodecConfig();
/// initializes the members required to manage the format: descriptors, reflector,
diff --git a/media/codec2/sfplugin/PipelineWatcher.cpp b/media/codec2/sfplugin/PipelineWatcher.cpp
index 74d14e8..0ee9056 100644
--- a/media/codec2/sfplugin/PipelineWatcher.cpp
+++ b/media/codec2/sfplugin/PipelineWatcher.cpp
@@ -146,7 +146,7 @@
std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count());
durations.push_back(elapsed);
}
- std::nth_element(durations.begin(), durations.end(), durations.begin() + n,
+ std::nth_element(durations.begin(), durations.begin() + n, durations.end(),
std::greater<Clock::duration>());
return durations[n];
}
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index b6ddfab..52cc7ad 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -66,7 +66,7 @@
"liblog",
"libnativewindow",
"libstagefright_foundation",
- "libstagefright_bufferpool@2.0",
+ "libstagefright_bufferpool@2.0.1",
"libui",
"libutils",
],
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
index 710b536..2d99b53 100644
--- a/media/codec2/vndk/C2Buffer.cpp
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -413,17 +413,14 @@
std::shared_ptr<C2LinearAllocation> alloc;
if (C2AllocatorIon::isValid(cHandle)) {
- native_handle_t *handle = native_handle_clone(cHandle);
- if (handle) {
- c2_status_t err = sAllocator->priorLinearAllocation(handle, &alloc);
- const std::shared_ptr<C2PooledBlockPoolData> poolData =
- std::make_shared<C2PooledBlockPoolData>(data);
- if (err == C2_OK && poolData) {
- // TODO: config params?
- std::shared_ptr<C2LinearBlock> block =
- _C2BlockFactory::CreateLinearBlock(alloc, poolData);
- return block;
- }
+ c2_status_t err = sAllocator->priorLinearAllocation(cHandle, &alloc);
+ const std::shared_ptr<C2PooledBlockPoolData> poolData =
+ std::make_shared<C2PooledBlockPoolData>(data);
+ if (err == C2_OK && poolData) {
+ // TODO: config params?
+ std::shared_ptr<C2LinearBlock> block =
+ _C2BlockFactory::CreateLinearBlock(alloc, poolData);
+ return block;
}
}
return nullptr;
@@ -674,17 +671,14 @@
ResultStatus status = mBufferPoolManager->allocate(
mConnectionId, params, &cHandle, &bufferPoolData);
if (status == ResultStatus::OK) {
- native_handle_t *handle = native_handle_clone(cHandle);
- if (handle) {
- std::shared_ptr<C2LinearAllocation> alloc;
- std::shared_ptr<C2PooledBlockPoolData> poolData =
- std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
- c2_status_t err = mAllocator->priorLinearAllocation(handle, &alloc);
- if (err == C2_OK && poolData && alloc) {
- *block = _C2BlockFactory::CreateLinearBlock(alloc, poolData, 0, capacity);
- if (*block) {
- return C2_OK;
- }
+ std::shared_ptr<C2LinearAllocation> alloc;
+ std::shared_ptr<C2PooledBlockPoolData> poolData =
+ std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
+ c2_status_t err = mAllocator->priorLinearAllocation(cHandle, &alloc);
+ if (err == C2_OK && poolData && alloc) {
+ *block = _C2BlockFactory::CreateLinearBlock(alloc, poolData, 0, capacity);
+ if (*block) {
+ return C2_OK;
}
}
return C2_NO_MEMORY;
@@ -710,19 +704,16 @@
ResultStatus status = mBufferPoolManager->allocate(
mConnectionId, params, &cHandle, &bufferPoolData);
if (status == ResultStatus::OK) {
- native_handle_t *handle = native_handle_clone(cHandle);
- if (handle) {
- std::shared_ptr<C2GraphicAllocation> alloc;
- std::shared_ptr<C2PooledBlockPoolData> poolData =
- std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
- c2_status_t err = mAllocator->priorGraphicAllocation(
- handle, &alloc);
- if (err == C2_OK && poolData && alloc) {
- *block = _C2BlockFactory::CreateGraphicBlock(
- alloc, poolData, C2Rect(width, height));
- if (*block) {
- return C2_OK;
- }
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ std::shared_ptr<C2PooledBlockPoolData> poolData =
+ std::make_shared<C2PooledBlockPoolData>(bufferPoolData);
+ c2_status_t err = mAllocator->priorGraphicAllocation(
+ cHandle, &alloc);
+ if (err == C2_OK && poolData && alloc) {
+ *block = _C2BlockFactory::CreateGraphicBlock(
+ alloc, poolData, C2Rect(width, height));
+ if (*block) {
+ return C2_OK;
}
}
return C2_NO_MEMORY;
@@ -1117,17 +1108,14 @@
std::shared_ptr<C2GraphicAllocation> alloc;
if (C2AllocatorGralloc::isValid(cHandle)) {
- native_handle_t *handle = native_handle_clone(cHandle);
- if (handle) {
- c2_status_t err = sAllocator->priorGraphicAllocation(handle, &alloc);
- const std::shared_ptr<C2PooledBlockPoolData> poolData =
- std::make_shared<C2PooledBlockPoolData>(data);
- if (err == C2_OK && poolData) {
- // TODO: config setup?
- std::shared_ptr<C2GraphicBlock> block =
- _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
- return block;
- }
+ c2_status_t err = sAllocator->priorGraphicAllocation(cHandle, &alloc);
+ const std::shared_ptr<C2PooledBlockPoolData> poolData =
+ std::make_shared<C2PooledBlockPoolData>(data);
+ if (err == C2_OK && poolData) {
+ // TODO: config setup?
+ std::shared_ptr<C2GraphicBlock> block =
+ _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+ return block;
}
}
return nullptr;
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index f8afa7c..5b2bd7b 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -848,7 +848,8 @@
emplace("libcodec2_soft_amrnbenc.so");
emplace("libcodec2_soft_amrwbdec.so");
emplace("libcodec2_soft_amrwbenc.so");
- emplace("libcodec2_soft_av1dec.so");
+ //emplace("libcodec2_soft_av1dec_aom.so"); // deprecated for the gav1 implementation
+ emplace("libcodec2_soft_av1dec_gav1.so");
emplace("libcodec2_soft_avcdec.so");
emplace("libcodec2_soft_avcenc.so");
emplace("libcodec2_soft_flacdec.so");
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 5a73d20..223d359 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -17,7 +17,6 @@
#ifndef FLAC_EXTRACTOR_H_
#define FLAC_EXTRACTOR_H_
-#include <media/DataSourceBase.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/NdkMediaFormat.h>
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index 2e78086..b486fc6 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -17,7 +17,6 @@
#ifndef MIDI_EXTRACTOR_H_
#define MIDI_EXTRACTOR_H_
-#include <media/DataSourceBase.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/stagefright/MediaBufferBase.h>
diff --git a/media/extractors/mp4/SampleIterator.cpp b/media/extractors/mp4/SampleIterator.cpp
index 0967652..85fbf97 100644
--- a/media/extractors/mp4/SampleIterator.cpp
+++ b/media/extractors/mp4/SampleIterator.cpp
@@ -22,7 +22,6 @@
#include <arpa/inet.h>
-#include <media/DataSourceBase.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index f4c277c..1d9e1e6 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -24,6 +24,7 @@
],
header_libs: [
+ "libaudioclient_headers",
"libbase_headers",
"libstagefright_headers",
"libmedia_headers",
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index 92ba039..002a855 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -23,7 +23,6 @@
#include "mpeg2ts/AnotherPacketSource.h"
#include "mpeg2ts/ESQueue.h"
-#include <media/DataSourceBase.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index 52eadd4..fb276c2 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -36,6 +36,7 @@
#include "binding/AAudioStreamConfiguration.h"
#include "binding/IAAudioService.h"
#include "binding/AAudioServiceMessage.h"
+#include "core/AudioGlobal.h"
#include "core/AudioStreamBuilder.h"
#include "fifo/FifoBuffer.h"
#include "utility/AudioClock.h"
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index a6cc45b..366cc87 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -89,7 +89,11 @@
if (mAudioEndpoint.isFreeRunning()) {
//ALOGD("AudioStreamInternalCapture::processDataNow() - update remote counter");
// Update data queue based on the timing model.
- int64_t estimatedRemoteCounter = mClockModel.convertTimeToPosition(currentNanoTime);
+ // Jitter in the DSP can cause late writes to the FIFO.
+ // This might be caused by resampling.
+ // We want to read the FIFO after the latest possible time
+ // that the DSP could have written the data.
+ int64_t estimatedRemoteCounter = mClockModel.convertLatestTimeToPosition(currentNanoTime);
// TODO refactor, maybe use setRemoteCounter()
mAudioEndpoint.setDataWriteCounter(estimatedRemoteCounter);
}
@@ -139,7 +143,7 @@
// the writeCounter might have just advanced in the background,
// causing us to sleep until a later burst.
int64_t nextPosition = mAudioEndpoint.getDataReadCounter() + mFramesPerBurst;
- wakeTime = mClockModel.convertPositionToTime(nextPosition);
+ wakeTime = mClockModel.convertPositionToLatestTime(nextPosition);
}
break;
default:
diff --git a/media/libaaudio/src/client/IsochronousClockModel.cpp b/media/libaaudio/src/client/IsochronousClockModel.cpp
index 747d0e1..9abdf53 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.cpp
+++ b/media/libaaudio/src/client/IsochronousClockModel.cpp
@@ -19,12 +19,11 @@
#include <log/log.h>
#include <stdint.h>
+#include <algorithm>
#include "utility/AudioClock.h"
#include "IsochronousClockModel.h"
-#define MIN_LATENESS_NANOS (10 * AAUDIO_NANOS_PER_MICROSECOND)
-
using namespace aaudio;
IsochronousClockModel::IsochronousClockModel()
@@ -32,7 +31,7 @@
, mMarkerNanoTime(0)
, mSampleRate(48000)
, mFramesPerBurst(64)
- , mMaxLatenessInNanos(0)
+ , mMaxMeasuredLatenessNanos(0)
, mState(STATE_STOPPED)
{
}
@@ -41,8 +40,7 @@
}
void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) {
- ALOGV("setPositionAndTime(%lld, %lld)",
- (long long) framePosition, (long long) nanoTime);
+ ALOGV("setPositionAndTime, %lld, %lld", (long long) framePosition, (long long) nanoTime);
mMarkerFramePosition = framePosition;
mMarkerNanoTime = nanoTime;
}
@@ -54,7 +52,9 @@
}
void IsochronousClockModel::stop(int64_t nanoTime) {
- ALOGV("stop(nanos = %lld)\n", (long long) nanoTime);
+ ALOGD("stop(nanos = %lld) max lateness = %d micros\n",
+ (long long) nanoTime,
+ (int) (mMaxMeasuredLatenessNanos / 1000));
setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime);
// TODO should we set position?
mState = STATE_STOPPED;
@@ -69,9 +69,10 @@
}
void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) {
-// ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu",
-// (long long)framePosition,
-// (long long)nanoTime);
+ mTimestampCount++;
+// Log position and time in CSV format so we can import it easily into spreadsheets.
+ //ALOGD("%s() CSV, %d, %lld, %lld", __func__,
+ //mTimestampCount, (long long)framePosition, (long long)nanoTime);
int64_t framesDelta = framePosition - mMarkerFramePosition;
int64_t nanosDelta = nanoTime - mMarkerNanoTime;
if (nanosDelta < 1000) {
@@ -108,17 +109,56 @@
case STATE_RUNNING:
if (nanosDelta < expectedNanosDelta) {
// Earlier than expected timestamp.
- // This data is probably more accurate so use it.
- // or we may be drifting due to a slow HW clock.
-// ALOGD("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY",
-// (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000));
+ // This data is probably more accurate, so use it.
+ // Or we may be drifting due to a fast HW clock.
+ //int microsDelta = (int) (nanosDelta / 1000);
+ //int expectedMicrosDelta = (int) (expectedNanosDelta / 1000);
+ //ALOGD("%s() - STATE_RUNNING - #%d, %4d micros EARLY",
+ //__func__, mTimestampCount, expectedMicrosDelta - microsDelta);
+
setPositionAndTime(framePosition, nanoTime);
- } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) {
- // Later than expected timestamp.
-// ALOGD("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE",
-// (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000),
-// (int) (mMaxLatenessInNanos / 1000));
- setPositionAndTime(framePosition - mFramesPerBurst, nanoTime - mMaxLatenessInNanos);
+ } else if (nanosDelta > (expectedNanosDelta + (2 * mBurstPeriodNanos))) {
+ // In this case we do not update mMaxMeasuredLatenessNanos because it
+ // would force it too high.
+ // mMaxMeasuredLatenessNanos should range from 1 to 2 * mBurstPeriodNanos
+ //int32_t measuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
+ //ALOGD("%s() - STATE_RUNNING - #%d, lateness %d - max %d = %4d micros VERY LATE",
+ //__func__,
+ //mTimestampCount,
+ //measuredLatenessNanos / 1000,
+ //mMaxMeasuredLatenessNanos / 1000,
+ //(measuredLatenessNanos - mMaxMeasuredLatenessNanos) / 1000
+ //);
+
+ // This typically happens when we are modelling a service instead of a DSP.
+ setPositionAndTime(framePosition, nanoTime - (2 * mBurstPeriodNanos));
+ } else if (nanosDelta > (expectedNanosDelta + mMaxMeasuredLatenessNanos)) {
+ //int32_t previousLatenessNanos = mMaxMeasuredLatenessNanos;
+ mMaxMeasuredLatenessNanos = (int32_t)(nanosDelta - expectedNanosDelta);
+
+ //ALOGD("%s() - STATE_RUNNING - #%d, newmax %d - oldmax %d = %4d micros LATE",
+ //__func__,
+ //mTimestampCount,
+ //mMaxMeasuredLatenessNanos / 1000,
+ //previousLatenessNanos / 1000,
+ //(mMaxMeasuredLatenessNanos - previousLatenessNanos) / 1000
+ //);
+
+ // When we are late, it may be because of preemption in the kernel,
+ // or timing jitter caused by resampling in the DSP,
+ // or we may be drifting due to a slow HW clock.
+ // We add slight drift value just in case there is actual long term drift
+ // forward caused by a slower clock.
+ // If the clock is faster than the model will get pushed earlier
+ // by the code in the preceding branch.
+ // The two opposing forces should allow the model to track the real clock
+ // over a long time.
+ int64_t driftingTime = mMarkerNanoTime + expectedNanosDelta + kDriftNanos;
+ setPositionAndTime(framePosition, driftingTime);
+ //ALOGD("%s() - #%d, max lateness = %d micros",
+ //__func__,
+ //mTimestampCount,
+ //(int) (mMaxMeasuredLatenessNanos / 1000));
}
break;
default:
@@ -138,9 +178,12 @@
update();
}
+// Update expected lateness based on sampleRate and framesPerBurst
void IsochronousClockModel::update() {
- int64_t nanosLate = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate
- mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS;
+ mBurstPeriodNanos = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate
+ // Timestamps may be late by up to a burst because we are randomly sampling the time period
+ // after the DSP position is actually updated.
+ mMaxMeasuredLatenessNanos = mBurstPeriodNanos;
}
int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const {
@@ -183,11 +226,25 @@
return position;
}
+int32_t IsochronousClockModel::getLateTimeOffsetNanos() const {
+ // This will never be < 0 because mMaxLatenessNanos starts at
+ // mBurstPeriodNanos and only gets bigger.
+ return (mMaxMeasuredLatenessNanos - mBurstPeriodNanos) + kExtraLatenessNanos;
+}
+
+int64_t IsochronousClockModel::convertPositionToLatestTime(int64_t framePosition) const {
+ return convertPositionToTime(framePosition) + getLateTimeOffsetNanos();
+}
+
+int64_t IsochronousClockModel::convertLatestTimeToPosition(int64_t nanoTime) const {
+ return convertTimeToPosition(nanoTime - getLateTimeOffsetNanos());
+}
+
void IsochronousClockModel::dump() const {
ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition);
ALOGD("mMarkerNanoTime = %lld", (long long) mMarkerNanoTime);
ALOGD("mSampleRate = %6d", mSampleRate);
ALOGD("mFramesPerBurst = %6d", mFramesPerBurst);
- ALOGD("mMaxLatenessInNanos = %6d", mMaxLatenessInNanos);
+ ALOGD("mMaxMeasuredLatenessNanos = %6d", mMaxMeasuredLatenessNanos);
ALOGD("mState = %6d", mState);
}
diff --git a/media/libaaudio/src/client/IsochronousClockModel.h b/media/libaaudio/src/client/IsochronousClockModel.h
index 46ca48e..582bf4e 100644
--- a/media/libaaudio/src/client/IsochronousClockModel.h
+++ b/media/libaaudio/src/client/IsochronousClockModel.h
@@ -18,6 +18,7 @@
#define ANDROID_AAUDIO_ISOCHRONOUS_CLOCK_MODEL_H
#include <stdint.h>
+#include "utility/AudioClock.h"
namespace aaudio {
@@ -79,6 +80,15 @@
int64_t convertPositionToTime(int64_t framePosition) const;
/**
+ * Calculate the latest estimated time that the stream will be at that position.
+ * The more jittery the clock is then the later this will be.
+ *
+ * @param framePosition
+ * @return time in nanoseconds
+ */
+ int64_t convertPositionToLatestTime(int64_t framePosition) const;
+
+ /**
* Calculate an estimated position where the stream will be at the specified time.
*
* @param nanoTime time of interest
@@ -87,6 +97,18 @@
int64_t convertTimeToPosition(int64_t nanoTime) const;
/**
+ * Calculate the corresponding estimated position based on the specified time being
+ * the latest possible time.
+ *
+ * For the same nanoTime, this may return an earlier position than
+ * convertTimeToPosition().
+ *
+ * @param nanoTime
+ * @return position in frames
+ */
+ int64_t convertLatestTimeToPosition(int64_t nanoTime) const;
+
+ /**
* @param framesDelta difference in frames
* @return duration in nanoseconds
*/
@@ -101,6 +123,9 @@
void dump() const;
private:
+
+ int32_t getLateTimeOffsetNanos() const;
+
enum clock_model_state_t {
STATE_STOPPED,
STATE_STARTING,
@@ -108,13 +133,23 @@
STATE_RUNNING
};
+ // Amount of time to drift forward when we get a late timestamp.
+ // This value was calculated to allow tracking of a clock with 50 ppm error.
+ static constexpr int32_t kDriftNanos = 10 * 1000;
+ // TODO review value of kExtraLatenessNanos
+ static constexpr int32_t kExtraLatenessNanos = 100 * 1000;
+
int64_t mMarkerFramePosition;
int64_t mMarkerNanoTime;
int32_t mSampleRate;
int32_t mFramesPerBurst;
- int32_t mMaxLatenessInNanos;
+ int32_t mBurstPeriodNanos;
+ // Includes mBurstPeriodNanos because we sample randomly over time.
+ int32_t mMaxMeasuredLatenessNanos;
clock_model_state_t mState;
+ int32_t mTimestampCount = 0;
+
void update();
};
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index d4a4f41..a23d945 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -43,6 +43,7 @@
],
header_libs: [
"android.hardware.audio.common.util@all-versions",
+ "libaudioclient_headers",
"libaudiohal_headers"
],
diff --git a/media/libdatasource/Android.bp b/media/libdatasource/Android.bp
new file mode 100644
index 0000000..dd8ef74
--- /dev/null
+++ b/media/libdatasource/Android.bp
@@ -0,0 +1,66 @@
+cc_library {
+ name: "libdatasource",
+
+ srcs: [
+ "ClearFileSource.cpp",
+ "ClearMediaHTTP.cpp",
+ "DataSourceFactory.cpp",
+ "DataURISource.cpp",
+ "FileSource.cpp",
+ "HTTPBase.cpp",
+ "MediaHTTP.cpp",
+ "NuCachedSource2.cpp",
+ ],
+
+ aidl: {
+ local_include_dirs: ["aidl"],
+ export_aidl_headers: true,
+ },
+
+ header_libs: [
+ "libstagefright_headers",
+ "media_ndk_headers",
+ "libmedia_headers",
+ ],
+
+ export_header_lib_headers: [
+ "libstagefright_headers",
+ "media_ndk_headers",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libdrmframework",
+ "libutils",
+ "libstagefright_foundation",
+ "libdl",
+ ],
+
+ static_libs: [
+ "libc_malloc_debug_backtrace", // for memory heap analysis
+ "libmedia_midiiowrapper",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
diff --git a/media/libstagefright/ClearFileSource.cpp b/media/libdatasource/ClearFileSource.cpp
similarity index 97%
rename from media/libstagefright/ClearFileSource.cpp
rename to media/libdatasource/ClearFileSource.cpp
index e3a2cb7..afafa23 100644
--- a/media/libstagefright/ClearFileSource.cpp
+++ b/media/libdatasource/ClearFileSource.cpp
@@ -18,9 +18,9 @@
#define LOG_TAG "ClearFileSource"
#include <utils/Log.h>
+#include <datasource/ClearFileSource.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ClearFileSource.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
diff --git a/media/libstagefright/http/ClearMediaHTTP.cpp b/media/libdatasource/ClearMediaHTTP.cpp
similarity index 97%
rename from media/libstagefright/http/ClearMediaHTTP.cpp
rename to media/libdatasource/ClearMediaHTTP.cpp
index 9557c8a..7249c84 100644
--- a/media/libstagefright/http/ClearMediaHTTP.cpp
+++ b/media/libdatasource/ClearMediaHTTP.cpp
@@ -18,11 +18,11 @@
#define LOG_TAG "ClearMediaHTTP"
#include <utils/Log.h>
-#include <media/stagefright/ClearMediaHTTP.h>
+#include <datasource/ClearMediaHTTP.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/MediaHTTPConnection.h>
diff --git a/media/libstagefright/DataSourceFactory.cpp b/media/libdatasource/DataSourceFactory.cpp
similarity index 93%
rename from media/libstagefright/DataSourceFactory.cpp
rename to media/libdatasource/DataSourceFactory.cpp
index 54bf0cc..8c772dd 100644
--- a/media/libstagefright/DataSourceFactory.cpp
+++ b/media/libdatasource/DataSourceFactory.cpp
@@ -16,15 +16,15 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "DataSource"
-#include "include/HTTPBase.h"
-#include "include/NuCachedSource2.h"
+#include <datasource/DataSourceFactory.h>
+#include <datasource/DataURISource.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/FileSource.h>
+#include <datasource/MediaHTTP.h>
+#include <datasource/NuCachedSource2.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/DataURISource.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaHTTP.h>
#include <utils/String8.h>
namespace android {
diff --git a/media/libstagefright/DataURISource.cpp b/media/libdatasource/DataURISource.cpp
similarity index 98%
rename from media/libstagefright/DataURISource.cpp
rename to media/libdatasource/DataURISource.cpp
index b975b38..216f3d0 100644
--- a/media/libstagefright/DataURISource.cpp
+++ b/media/libdatasource/DataURISource.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include <media/stagefright/DataURISource.h>
+#include <datasource/DataURISource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AString.h>
diff --git a/media/libstagefright/FileSource.cpp b/media/libdatasource/FileSource.cpp
similarity index 97%
rename from media/libstagefright/FileSource.cpp
rename to media/libdatasource/FileSource.cpp
index aee7fd8..65780e3 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libdatasource/FileSource.cpp
@@ -18,9 +18,8 @@
#define LOG_TAG "FileSource"
#include <utils/Log.h>
+#include <datasource/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/FileSource.h>
-#include <media/stagefright/Utils.h>
#include <private/android_filesystem_config.h>
namespace android {
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libdatasource/HTTPBase.cpp
similarity index 98%
rename from media/libstagefright/HTTPBase.cpp
rename to media/libdatasource/HTTPBase.cpp
index d118e8c..ef29c48 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libdatasource/HTTPBase.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "HTTPBase"
#include <utils/Log.h>
-#include "include/HTTPBase.h"
+#include <datasource/HTTPBase.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libdatasource/MediaHTTP.cpp
similarity index 95%
rename from media/libstagefright/http/MediaHTTP.cpp
rename to media/libdatasource/MediaHTTP.cpp
index 0fba3dc..e57510d 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libdatasource/MediaHTTP.cpp
@@ -18,12 +18,12 @@
#define LOG_TAG "MediaHTTP"
#include <utils/Log.h>
-#include <media/stagefright/MediaHTTP.h>
+#include <datasource/MediaHTTP.h>
#include <binder/IServiceManager.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/MediaHTTPConnection.h>
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libdatasource/NuCachedSource2.cpp
similarity index 99%
rename from media/libstagefright/NuCachedSource2.cpp
rename to media/libdatasource/NuCachedSource2.cpp
index 522c81d..7f5ae61 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libdatasource/NuCachedSource2.cpp
@@ -20,8 +20,8 @@
#define LOG_TAG "NuCachedSource2"
#include <utils/Log.h>
-#include "include/NuCachedSource2.h"
-#include "include/HTTPBase.h"
+#include <datasource/NuCachedSource2.h>
+#include <datasource/HTTPBase.h>
#include <cutils/properties.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libstagefright/include/media/stagefright/ClearFileSource.h b/media/libdatasource/include/datasource/ClearFileSource.h
similarity index 100%
rename from media/libstagefright/include/media/stagefright/ClearFileSource.h
rename to media/libdatasource/include/datasource/ClearFileSource.h
diff --git a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h b/media/libdatasource/include/datasource/ClearMediaHTTP.h
similarity index 97%
rename from media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
rename to media/libdatasource/include/datasource/ClearMediaHTTP.h
index 72907a9..5440a3a 100644
--- a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
+++ b/media/libdatasource/include/datasource/ClearMediaHTTP.h
@@ -20,7 +20,7 @@
#include <media/stagefright/foundation/AString.h>
-#include "include/HTTPBase.h"
+#include "HTTPBase.h"
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/DataSourceFactory.h b/media/libdatasource/include/datasource/DataSourceFactory.h
similarity index 95%
rename from media/libstagefright/include/media/stagefright/DataSourceFactory.h
rename to media/libdatasource/include/datasource/DataSourceFactory.h
index 2a1d491..6e313d3 100644
--- a/media/libstagefright/include/media/stagefright/DataSourceFactory.h
+++ b/media/libdatasource/include/datasource/DataSourceFactory.h
@@ -18,7 +18,9 @@
#define DATA_SOURCE_FACTORY_H_
+#include <media/DataSource.h>
#include <sys/types.h>
+#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
namespace android {
diff --git a/media/libstagefright/include/media/stagefright/DataURISource.h b/media/libdatasource/include/datasource/DataURISource.h
similarity index 100%
rename from media/libstagefright/include/media/stagefright/DataURISource.h
rename to media/libdatasource/include/datasource/DataURISource.h
diff --git a/media/libstagefright/include/media/stagefright/FileSource.h b/media/libdatasource/include/datasource/FileSource.h
similarity index 96%
rename from media/libstagefright/include/media/stagefright/FileSource.h
rename to media/libdatasource/include/datasource/FileSource.h
index b610eef..9249842 100644
--- a/media/libstagefright/include/media/stagefright/FileSource.h
+++ b/media/libdatasource/include/datasource/FileSource.h
@@ -20,7 +20,7 @@
#include <stdio.h>
-#include <media/stagefright/ClearFileSource.h>
+#include <datasource/ClearFileSource.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/threads.h>
#include <drm/DrmManagerClient.h>
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libdatasource/include/datasource/HTTPBase.h
similarity index 100%
rename from media/libstagefright/include/HTTPBase.h
rename to media/libdatasource/include/datasource/HTTPBase.h
diff --git a/media/libstagefright/include/media/stagefright/MediaHTTP.h b/media/libdatasource/include/datasource/MediaHTTP.h
similarity index 95%
rename from media/libstagefright/include/media/stagefright/MediaHTTP.h
rename to media/libdatasource/include/datasource/MediaHTTP.h
index acaa6c4..60252ce 100644
--- a/media/libstagefright/include/media/stagefright/MediaHTTP.h
+++ b/media/libdatasource/include/datasource/MediaHTTP.h
@@ -18,8 +18,8 @@
#define MEDIA_HTTP_H_
+#include <datasource/ClearMediaHTTP.h>
#include <media/stagefright/foundation/AString.h>
-#include <media/stagefright/ClearMediaHTTP.h>
namespace android {
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libdatasource/include/datasource/NuCachedSource2.h
similarity index 100%
rename from media/libstagefright/include/NuCachedSource2.h
rename to media/libdatasource/include/datasource/NuCachedSource2.h
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 3fbbc09..10dda19 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -302,6 +302,8 @@
for (int i = 0; i < FIVEBAND_NUMBANDS; i++) {
pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i];
}
+ pContext->pBundledContext->effectProcessCalled = 0;
+ pContext->pBundledContext->effectInDrain = 0;
ALOGV("\tEffectCreate - Calling LvmBundle_init");
ret = LvmBundle_init(pContext);
@@ -394,6 +396,8 @@
// Clear the instantiated flag for the effect
// protect agains the case where an effect is un-instantiated without being disabled
+
+ int &effectInDrain = pContext->pBundledContext->effectInDrain;
if(pContext->EffectType == LVM_BASS_BOOST) {
ALOGV("\tEffectRelease LVM_BASS_BOOST Clearing global intstantiated flag");
pSessionContext->bBassInstantiated = LVM_FALSE;
@@ -418,12 +422,16 @@
} else if(pContext->EffectType == LVM_VOLUME) {
ALOGV("\tEffectRelease LVM_VOLUME Clearing global intstantiated flag");
pSessionContext->bVolumeInstantiated = LVM_FALSE;
- if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE){
+ // There is no samplesToExitCount for volume so we also use the drain flag to check
+ // if we should decrement the effects enabled.
+ if (pContext->pBundledContext->bVolumeEnabled == LVM_TRUE
+ || (effectInDrain & 1 << LVM_VOLUME) != 0) {
pContext->pBundledContext->NumberEffectsEnabled--;
}
} else {
ALOGV("\tLVM_ERROR : EffectRelease : Unsupported effect\n\n\n\n\n\n\n");
}
+ effectInDrain &= ~(1 << pContext->EffectType); // no need to drain if released
// Disable effect, in this case ignore errors (return codes)
// if an effect has already been disabled
@@ -3124,8 +3132,9 @@
int Effect_setEnabled(EffectContext *pContext, bool enabled)
{
- ALOGV("\tEffect_setEnabled() type %d, enabled %d", pContext->EffectType, enabled);
-
+ ALOGV("%s effectType %d, enabled %d, currently enabled %d", __func__,
+ pContext->EffectType, enabled, pContext->pBundledContext->NumberEffectsEnabled);
+ int &effectInDrain = pContext->pBundledContext->effectInDrain;
if (enabled) {
// Bass boost or Virtualizer can be temporarily disabled if playing over device speaker due
// to their nature.
@@ -3139,6 +3148,7 @@
if(pContext->pBundledContext->SamplesToExitCountBb <= 0){
pContext->pBundledContext->NumberEffectsEnabled++;
}
+ effectInDrain &= ~(1 << LVM_BASS_BOOST);
pContext->pBundledContext->SamplesToExitCountBb =
(LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
pContext->pBundledContext->bBassEnabled = LVM_TRUE;
@@ -3152,6 +3162,7 @@
if(pContext->pBundledContext->SamplesToExitCountEq <= 0){
pContext->pBundledContext->NumberEffectsEnabled++;
}
+ effectInDrain &= ~(1 << LVM_EQUALIZER);
pContext->pBundledContext->SamplesToExitCountEq =
(LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
pContext->pBundledContext->bEqualizerEnabled = LVM_TRUE;
@@ -3164,6 +3175,7 @@
if(pContext->pBundledContext->SamplesToExitCountVirt <= 0){
pContext->pBundledContext->NumberEffectsEnabled++;
}
+ effectInDrain &= ~(1 << LVM_VIRTUALIZER);
pContext->pBundledContext->SamplesToExitCountVirt =
(LVM_INT32)(pContext->pBundledContext->SamplesPerSecond*0.1);
pContext->pBundledContext->bVirtualizerEnabled = LVM_TRUE;
@@ -3174,7 +3186,10 @@
ALOGV("\tEffect_setEnabled() LVM_VOLUME is already enabled");
return -EINVAL;
}
- pContext->pBundledContext->NumberEffectsEnabled++;
+ if ((effectInDrain & 1 << LVM_VOLUME) == 0) {
+ pContext->pBundledContext->NumberEffectsEnabled++;
+ }
+ effectInDrain &= ~(1 << LVM_VOLUME);
pContext->pBundledContext->bVolumeEnabled = LVM_TRUE;
break;
default:
@@ -3192,6 +3207,7 @@
return -EINVAL;
}
pContext->pBundledContext->bBassEnabled = LVM_FALSE;
+ effectInDrain |= 1 << LVM_BASS_BOOST;
break;
case LVM_EQUALIZER:
if (pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE) {
@@ -3199,6 +3215,7 @@
return -EINVAL;
}
pContext->pBundledContext->bEqualizerEnabled = LVM_FALSE;
+ effectInDrain |= 1 << LVM_EQUALIZER;
break;
case LVM_VIRTUALIZER:
if (pContext->pBundledContext->bVirtualizerEnabled == LVM_FALSE) {
@@ -3206,6 +3223,7 @@
return -EINVAL;
}
pContext->pBundledContext->bVirtualizerEnabled = LVM_FALSE;
+ effectInDrain |= 1 << LVM_VIRTUALIZER;
break;
case LVM_VOLUME:
if (pContext->pBundledContext->bVolumeEnabled == LVM_FALSE) {
@@ -3213,6 +3231,7 @@
return -EINVAL;
}
pContext->pBundledContext->bVolumeEnabled = LVM_FALSE;
+ effectInDrain |= 1 << LVM_VOLUME;
break;
default:
ALOGV("\tEffect_setEnabled() invalid effect type");
@@ -3283,6 +3302,38 @@
ALOGV("\tLVM_ERROR : Effect_process() ERROR NULL INPUT POINTER OR FRAME COUNT IS WRONG");
return -EINVAL;
}
+
+ int &effectProcessCalled = pContext->pBundledContext->effectProcessCalled;
+ int &effectInDrain = pContext->pBundledContext->effectInDrain;
+ if ((effectProcessCalled & 1 << pContext->EffectType) != 0) {
+ ALOGW("Effect %d already called", pContext->EffectType);
+ const int undrainedEffects = effectInDrain & ~effectProcessCalled;
+ if ((undrainedEffects & 1 << LVM_BASS_BOOST) != 0) {
+ ALOGW("Draining BASS_BOOST");
+ pContext->pBundledContext->SamplesToExitCountBb = 0;
+ --pContext->pBundledContext->NumberEffectsEnabled;
+ effectInDrain &= ~(1 << LVM_BASS_BOOST);
+ }
+ if ((undrainedEffects & 1 << LVM_EQUALIZER) != 0) {
+ ALOGW("Draining EQUALIZER");
+ pContext->pBundledContext->SamplesToExitCountEq = 0;
+ --pContext->pBundledContext->NumberEffectsEnabled;
+ effectInDrain &= ~(1 << LVM_EQUALIZER);
+ }
+ if ((undrainedEffects & 1 << LVM_VIRTUALIZER) != 0) {
+ ALOGW("Draining VIRTUALIZER");
+ pContext->pBundledContext->SamplesToExitCountVirt = 0;
+ --pContext->pBundledContext->NumberEffectsEnabled;
+ effectInDrain &= ~(1 << LVM_VIRTUALIZER);
+ }
+ if ((undrainedEffects & 1 << LVM_VOLUME) != 0) {
+ ALOGW("Draining VOLUME");
+ --pContext->pBundledContext->NumberEffectsEnabled;
+ effectInDrain &= ~(1 << LVM_VOLUME);
+ }
+ }
+ effectProcessCalled |= 1 << pContext->EffectType;
+
if ((pContext->pBundledContext->bBassEnabled == LVM_FALSE)&&
(pContext->EffectType == LVM_BASS_BOOST)){
//ALOGV("\tEffect_process() LVM_BASS_BOOST Effect is not enabled");
@@ -3291,9 +3342,12 @@
//ALOGV("\tEffect_process: Waiting to turn off BASS_BOOST, %d samples left",
// pContext->pBundledContext->SamplesToExitCountBb);
}
- if(pContext->pBundledContext->SamplesToExitCountBb <= 0) {
+ if (pContext->pBundledContext->SamplesToExitCountBb <= 0) {
status = -ENODATA;
- pContext->pBundledContext->NumberEffectsEnabled--;
+ if ((effectInDrain & 1 << LVM_BASS_BOOST) != 0) {
+ pContext->pBundledContext->NumberEffectsEnabled--;
+ effectInDrain &= ~(1 << LVM_BASS_BOOST);
+ }
ALOGV("\tEffect_process() this is the last frame for LVM_BASS_BOOST");
}
}
@@ -3301,7 +3355,10 @@
(pContext->EffectType == LVM_VOLUME)){
//ALOGV("\tEffect_process() LVM_VOLUME Effect is not enabled");
status = -ENODATA;
- pContext->pBundledContext->NumberEffectsEnabled--;
+ if ((effectInDrain & 1 << LVM_VOLUME) != 0) {
+ pContext->pBundledContext->NumberEffectsEnabled--;
+ effectInDrain &= ~(1 << LVM_VOLUME);
+ }
}
if ((pContext->pBundledContext->bEqualizerEnabled == LVM_FALSE)&&
(pContext->EffectType == LVM_EQUALIZER)){
@@ -3311,9 +3368,12 @@
//ALOGV("\tEffect_process: Waiting to turn off EQUALIZER, %d samples left",
// pContext->pBundledContext->SamplesToExitCountEq);
}
- if(pContext->pBundledContext->SamplesToExitCountEq <= 0) {
+ if (pContext->pBundledContext->SamplesToExitCountEq <= 0) {
status = -ENODATA;
- pContext->pBundledContext->NumberEffectsEnabled--;
+ if ((effectInDrain & 1 << LVM_EQUALIZER) != 0) {
+ pContext->pBundledContext->NumberEffectsEnabled--;
+ effectInDrain &= ~(1 << LVM_EQUALIZER);
+ }
ALOGV("\tEffect_process() this is the last frame for LVM_EQUALIZER");
}
}
@@ -3326,9 +3386,12 @@
//ALOGV("\tEffect_process: Waiting for to turn off VIRTUALIZER, %d samples left",
// pContext->pBundledContext->SamplesToExitCountVirt);
}
- if(pContext->pBundledContext->SamplesToExitCountVirt <= 0) {
+ if (pContext->pBundledContext->SamplesToExitCountVirt <= 0) {
status = -ENODATA;
- pContext->pBundledContext->NumberEffectsEnabled--;
+ if ((effectInDrain & 1 << LVM_VIRTUALIZER) != 0) {
+ pContext->pBundledContext->NumberEffectsEnabled--;
+ effectInDrain &= ~(1 << LVM_VIRTUALIZER);
+ }
ALOGV("\tEffect_process() this is the last frame for LVM_VIRTUALIZER");
}
}
@@ -3337,8 +3400,18 @@
pContext->pBundledContext->NumberEffectsCalled++;
}
- if(pContext->pBundledContext->NumberEffectsCalled ==
- pContext->pBundledContext->NumberEffectsEnabled){
+ if (pContext->pBundledContext->NumberEffectsCalled >=
+ pContext->pBundledContext->NumberEffectsEnabled) {
+
+ // We expect the # effects called to be equal to # effects enabled in sequence (including
+ // draining effects). Warn if this is not the case due to inconsistent calls.
+ ALOGW_IF(pContext->pBundledContext->NumberEffectsCalled >
+ pContext->pBundledContext->NumberEffectsEnabled,
+ "%s Number of effects called %d is greater than number of effects enabled %d",
+ __func__, pContext->pBundledContext->NumberEffectsCalled,
+ pContext->pBundledContext->NumberEffectsEnabled);
+ effectProcessCalled = 0; // reset our consistency check.
+
//ALOGV("\tEffect_process Calling process with %d effects enabled, %d called: Effect %d",
//pContext->pBundledContext->NumberEffectsEnabled,
//pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
index 6af4554..e4aacd0 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h
@@ -110,6 +110,14 @@
#ifdef SUPPORT_MC
LVM_INT32 ChMask;
#endif
+
+ /* Bitmask whether drain is in progress due to disabling the effect.
+ The corresponding bit to an effect is set by 1 << lvm_effect_en. */
+ int effectInDrain;
+
+ /* Bitmask whether process() was called for a particular effect.
+ The corresponding bit to an effect is set by 1 << lvm_effect_en. */
+ int effectProcessCalled;
};
/* SessionContext : One session */
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index dec2432..fdab14a 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -60,10 +60,8 @@
srcs: [
":libmedia_omx_aidl",
- "IMediaCodecList.cpp",
"IOMX.cpp",
"MediaCodecBuffer.cpp",
- "MediaCodecInfo.cpp",
"OMXBuffer.cpp",
"omx/1.0/WGraphicBufferSource.cpp",
"omx/1.0/WOmxBufferSource.cpp",
@@ -217,6 +215,49 @@
},
}
+cc_library_shared {
+ name: "libmedia_codeclist",
+
+ srcs: [
+ "IMediaCodecList.cpp",
+ "MediaCodecInfo.cpp",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ shared_libs: [
+ "android.hardware.media.omx@1.0",
+ "libbinder",
+ "liblog",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+
+ include_dirs: [
+ "system/libhidl/transport/token/1.0/utils/include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ },
+}
+
cc_library {
name: "libmedia",
@@ -245,7 +286,6 @@
"IMediaMetadataRetriever.cpp",
"mediametadataretriever.cpp",
"MidiDeviceInfo.cpp",
- "JetPlayer.cpp",
"MediaScanner.cpp",
"MediaScannerClient.cpp",
"CharacterEncodingDetector.cpp",
@@ -291,6 +331,7 @@
"libdl",
"libaudioutils",
"libaudioclient",
+ "libmedia_codeclist",
"libmedia_omx",
],
@@ -304,7 +345,6 @@
static_libs: [
"libc_malloc_debug_backtrace", // for memory heap analysis
- "libmedia_midiiowrapper",
],
export_include_dirs: [
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
index 9724fc1..f8a0a14 100644
--- a/media/libmedia/IResourceManagerService.cpp
+++ b/media/libmedia/IResourceManagerService.cpp
@@ -32,6 +32,7 @@
CONFIG = IBinder::FIRST_CALL_TRANSACTION,
ADD_RESOURCE,
REMOVE_RESOURCE,
+ REMOVE_CLIENT,
RECLAIM_RESOURCE,
};
@@ -72,12 +73,14 @@
virtual void addResource(
int pid,
+ int uid,
int64_t clientId,
const sp<IResourceManagerClient> client,
const Vector<MediaResource> &resources) {
Parcel data, reply;
data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
data.writeInt32(pid);
+ data.writeInt32(uid);
data.writeInt64(clientId);
data.writeStrongBinder(IInterface::asBinder(client));
writeToParcel(&data, resources);
@@ -85,13 +88,23 @@
remote()->transact(ADD_RESOURCE, data, &reply);
}
- virtual void removeResource(int pid, int64_t clientId) {
+ virtual void removeResource(int pid, int64_t clientId, const Vector<MediaResource> &resources) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
+ data.writeInt32(pid);
+ data.writeInt64(clientId);
+ writeToParcel(&data, resources);
+
+ remote()->transact(REMOVE_RESOURCE, data, &reply);
+ }
+
+ virtual void removeClient(int pid, int64_t clientId) {
Parcel data, reply;
data.writeInterfaceToken(IResourceManagerService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeInt64(clientId);
- remote()->transact(REMOVE_RESOURCE, data, &reply);
+ remote()->transact(REMOVE_CLIENT, data, &reply);
}
virtual bool reclaimResource(int callingPid, const Vector<MediaResource> &resources) {
@@ -129,6 +142,7 @@
case ADD_RESOURCE: {
CHECK_INTERFACE(IResourceManagerService, data, reply);
int pid = data.readInt32();
+ int uid = data.readInt32();
int64_t clientId = data.readInt64();
sp<IResourceManagerClient> client(
interface_cast<IResourceManagerClient>(data.readStrongBinder()));
@@ -137,7 +151,7 @@
}
Vector<MediaResource> resources;
readFromParcel(data, &resources);
- addResource(pid, clientId, client, resources);
+ addResource(pid, uid, clientId, client, resources);
return NO_ERROR;
} break;
@@ -145,7 +159,17 @@
CHECK_INTERFACE(IResourceManagerService, data, reply);
int pid = data.readInt32();
int64_t clientId = data.readInt64();
- removeResource(pid, clientId);
+ Vector<MediaResource> resources;
+ readFromParcel(data, &resources);
+ removeResource(pid, clientId, resources);
+ return NO_ERROR;
+ } break;
+
+ case REMOVE_CLIENT: {
+ CHECK_INTERFACE(IResourceManagerService, data, reply);
+ int pid = data.readInt32();
+ int64_t clientId = data.readInt64();
+ removeClient(pid, clientId);
return NO_ERROR;
} break;
diff --git a/media/libmedia/JetPlayer.cpp b/media/libmedia/JetPlayer.cpp
deleted file mode 100644
index 0d3c1ba..0000000
--- a/media/libmedia/JetPlayer.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright (C) 2008 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 "JetPlayer-C"
-
-#include <utils/Log.h>
-#include <media/JetPlayer.h>
-
-
-namespace android
-{
-
-static const int MIX_NUM_BUFFERS = 4;
-static const S_EAS_LIB_CONFIG* pLibConfig = NULL;
-
-//-------------------------------------------------------------------------------------------------
-JetPlayer::JetPlayer(void *javaJetPlayer, int maxTracks, int trackBufferSize) :
- mEventCallback(NULL),
- mJavaJetPlayerRef(javaJetPlayer),
- mTid(-1),
- mRender(false),
- mPaused(false),
- mMaxTracks(maxTracks),
- mEasData(NULL),
- mIoWrapper(NULL),
- mTrackBufferSize(trackBufferSize)
-{
- ALOGV("JetPlayer constructor");
- mPreviousJetStatus.currentUserID = -1;
- mPreviousJetStatus.segmentRepeatCount = -1;
- mPreviousJetStatus.numQueuedSegments = -1;
- mPreviousJetStatus.paused = true;
-}
-
-//-------------------------------------------------------------------------------------------------
-JetPlayer::~JetPlayer()
-{
- ALOGV("~JetPlayer");
- release();
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::init()
-{
- //Mutex::Autolock lock(&mMutex);
-
- EAS_RESULT result;
-
- // retrieve the EAS library settings
- if (pLibConfig == NULL)
- pLibConfig = EAS_Config();
- if (pLibConfig == NULL) {
- ALOGE("JetPlayer::init(): EAS library configuration could not be retrieved, aborting.");
- return EAS_FAILURE;
- }
-
- // init the EAS library
- result = EAS_Init(&mEasData);
- if (result != EAS_SUCCESS) {
- ALOGE("JetPlayer::init(): Error initializing Sonivox EAS library, aborting.");
- mState = EAS_STATE_ERROR;
- return result;
- }
- // init the JET library with the default app event controller range
- result = JET_Init(mEasData, NULL, sizeof(S_JET_CONFIG));
- if (result != EAS_SUCCESS) {
- ALOGE("JetPlayer::init(): Error initializing JET library, aborting.");
- mState = EAS_STATE_ERROR;
- return result;
- }
-
- // create the output AudioTrack
- mAudioTrack = new AudioTrack();
- status_t status = mAudioTrack->set(AUDIO_STREAM_MUSIC, //TODO parameterize this
- pLibConfig->sampleRate,
- AUDIO_FORMAT_PCM_16_BIT,
- audio_channel_out_mask_from_count(pLibConfig->numChannels),
- (size_t) mTrackBufferSize,
- AUDIO_OUTPUT_FLAG_NONE);
- if (status != OK) {
- ALOGE("JetPlayer::init(): Error initializing JET library; AudioTrack error %d", status);
- mAudioTrack.clear();
- mState = EAS_STATE_ERROR;
- return EAS_FAILURE;
- }
-
- // create render and playback thread
- {
- Mutex::Autolock l(mMutex);
- ALOGV("JetPlayer::init(): trying to start render thread");
- mThread = new JetPlayerThread(this);
- mThread->run("jetRenderThread", ANDROID_PRIORITY_AUDIO);
- mCondition.wait(mMutex);
- }
- if (mTid > 0) {
- // render thread started, we're ready
- ALOGV("JetPlayer::init(): render thread(%d) successfully started.", mTid);
- mState = EAS_STATE_READY;
- } else {
- ALOGE("JetPlayer::init(): failed to start render thread.");
- mState = EAS_STATE_ERROR;
- return EAS_FAILURE;
- }
-
- return EAS_SUCCESS;
-}
-
-void JetPlayer::setEventCallback(jetevent_callback eventCallback)
-{
- Mutex::Autolock l(mMutex);
- mEventCallback = eventCallback;
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::release()
-{
- ALOGV("JetPlayer::release()");
- Mutex::Autolock lock(mMutex);
- mPaused = true;
- mRender = false;
- if (mEasData) {
- JET_Pause(mEasData);
- JET_CloseFile(mEasData);
- JET_Shutdown(mEasData);
- EAS_Shutdown(mEasData);
- }
- delete mIoWrapper;
- mIoWrapper = NULL;
- if (mAudioTrack != 0) {
- mAudioTrack->stop();
- mAudioTrack->flush();
- mAudioTrack.clear();
- }
- if (mAudioBuffer) {
- delete mAudioBuffer;
- mAudioBuffer = NULL;
- }
- mEasData = NULL;
-
- return EAS_SUCCESS;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::render() {
- EAS_RESULT result = EAS_FAILURE;
- EAS_I32 count;
- int temp;
- bool audioStarted = false;
-
- ALOGV("JetPlayer::render(): entering");
-
- // allocate render buffer
- mAudioBuffer =
- new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * MIX_NUM_BUFFERS];
-
- // signal main thread that we started
- {
- Mutex::Autolock l(mMutex);
- mTid = gettid();
- ALOGV("JetPlayer::render(): render thread(%d) signal", mTid);
- mCondition.signal();
- }
-
- while (1) {
-
- mMutex.lock(); // [[[[[[[[ LOCK ---------------------------------------
-
- if (mEasData == NULL) {
- mMutex.unlock();
- ALOGV("JetPlayer::render(): NULL EAS data, exiting render.");
- goto threadExit;
- }
-
- // nothing to render, wait for client thread to wake us up
- while (!mRender)
- {
- ALOGV("JetPlayer::render(): signal wait");
- if (audioStarted) {
- mAudioTrack->pause();
- // we have to restart the playback once we start rendering again
- audioStarted = false;
- }
- mCondition.wait(mMutex);
- ALOGV("JetPlayer::render(): signal rx'd");
- }
-
- // render midi data into the input buffer
- int num_output = 0;
- EAS_PCM* p = mAudioBuffer;
- for (int i = 0; i < MIX_NUM_BUFFERS; i++) {
- result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count);
- if (result != EAS_SUCCESS) {
- ALOGE("JetPlayer::render(): EAS_Render returned error %ld", result);
- }
- p += count * pLibConfig->numChannels;
- num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM);
-
- // send events that were generated (if any) to the event callback
- fireEventsFromJetQueue();
- }
-
- // update playback state
- //ALOGV("JetPlayer::render(): updating state");
- JET_Status(mEasData, &mJetStatus);
- fireUpdateOnStatusChange();
- mPaused = mJetStatus.paused;
-
- mMutex.unlock(); // UNLOCK ]]]]]]]] -----------------------------------
-
- // check audio output track
- if (mAudioTrack == NULL) {
- ALOGE("JetPlayer::render(): output AudioTrack was not created");
- goto threadExit;
- }
-
- // Write data to the audio hardware
- //ALOGV("JetPlayer::render(): writing to audio output");
- if ((temp = mAudioTrack->write(mAudioBuffer, num_output)) < 0) {
- ALOGE("JetPlayer::render(): Error in writing:%d",temp);
- return temp;
- }
-
- // start audio output if necessary
- if (!audioStarted) {
- ALOGV("JetPlayer::render(): starting audio playback");
- mAudioTrack->start();
- audioStarted = true;
- }
-
- }//while (1)
-
-threadExit:
- if (mAudioTrack != NULL) {
- mAudioTrack->stop();
- mAudioTrack->flush();
- }
- delete [] mAudioBuffer;
- mAudioBuffer = NULL;
- mMutex.lock();
- mTid = -1;
- mCondition.signal();
- mMutex.unlock();
- return result;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-// fire up an update if any of the status fields has changed
-// precondition: mMutex locked
-void JetPlayer::fireUpdateOnStatusChange()
-{
- if ( (mJetStatus.currentUserID != mPreviousJetStatus.currentUserID)
- ||(mJetStatus.segmentRepeatCount != mPreviousJetStatus.segmentRepeatCount) ) {
- if (mEventCallback) {
- mEventCallback(
- JetPlayer::JET_USERID_UPDATE,
- mJetStatus.currentUserID,
- mJetStatus.segmentRepeatCount,
- mJavaJetPlayerRef);
- }
- mPreviousJetStatus.currentUserID = mJetStatus.currentUserID;
- mPreviousJetStatus.segmentRepeatCount = mJetStatus.segmentRepeatCount;
- }
-
- if (mJetStatus.numQueuedSegments != mPreviousJetStatus.numQueuedSegments) {
- if (mEventCallback) {
- mEventCallback(
- JetPlayer::JET_NUMQUEUEDSEGMENT_UPDATE,
- mJetStatus.numQueuedSegments,
- -1,
- mJavaJetPlayerRef);
- }
- mPreviousJetStatus.numQueuedSegments = mJetStatus.numQueuedSegments;
- }
-
- if (mJetStatus.paused != mPreviousJetStatus.paused) {
- if (mEventCallback) {
- mEventCallback(JetPlayer::JET_PAUSE_UPDATE,
- mJetStatus.paused,
- -1,
- mJavaJetPlayerRef);
- }
- mPreviousJetStatus.paused = mJetStatus.paused;
- }
-
-}
-
-
-//-------------------------------------------------------------------------------------------------
-// fire up all the JET events in the JET engine queue (until the queue is empty)
-// precondition: mMutex locked
-void JetPlayer::fireEventsFromJetQueue()
-{
- if (!mEventCallback) {
- // no callback, just empty the event queue
- while (JET_GetEvent(mEasData, NULL, NULL)) { }
- return;
- }
-
- EAS_U32 rawEvent;
- while (JET_GetEvent(mEasData, &rawEvent, NULL)) {
- mEventCallback(
- JetPlayer::JET_EVENT,
- rawEvent,
- -1,
- mJavaJetPlayerRef);
- }
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::loadFromFile(const char* path)
-{
- ALOGV("JetPlayer::loadFromFile(): path=%s", path);
-
- Mutex::Autolock lock(mMutex);
-
- delete mIoWrapper;
- mIoWrapper = new MidiIoWrapper(path);
-
- EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
- if (result != EAS_SUCCESS)
- mState = EAS_STATE_ERROR;
- else
- mState = EAS_STATE_OPEN;
- return( result );
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::loadFromFD(const int fd, const long long offset, const long long length)
-{
- ALOGV("JetPlayer::loadFromFD(): fd=%d offset=%lld length=%lld", fd, offset, length);
-
- Mutex::Autolock lock(mMutex);
-
- delete mIoWrapper;
- mIoWrapper = new MidiIoWrapper(fd, offset, length);
-
- EAS_RESULT result = JET_OpenFile(mEasData, mIoWrapper->getLocator());
- if (result != EAS_SUCCESS)
- mState = EAS_STATE_ERROR;
- else
- mState = EAS_STATE_OPEN;
- return( result );
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::closeFile()
-{
- Mutex::Autolock lock(mMutex);
- return JET_CloseFile(mEasData);
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::play()
-{
- ALOGV("JetPlayer::play(): entering");
- Mutex::Autolock lock(mMutex);
-
- EAS_RESULT result = JET_Play(mEasData);
-
- mPaused = false;
- mRender = true;
-
- JET_Status(mEasData, &mJetStatus);
- this->dumpJetStatus(&mJetStatus);
-
- fireUpdateOnStatusChange();
-
- // wake up render thread
- ALOGV("JetPlayer::play(): wakeup render thread");
- mCondition.signal();
-
- return result;
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::pause()
-{
- Mutex::Autolock lock(mMutex);
- mPaused = true;
- EAS_RESULT result = JET_Pause(mEasData);
-
- mRender = false;
-
- JET_Status(mEasData, &mJetStatus);
- this->dumpJetStatus(&mJetStatus);
- fireUpdateOnStatusChange();
-
-
- return result;
-}
-
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
- EAS_U32 muteFlags, EAS_U8 userID)
-{
- ALOGV("JetPlayer::queueSegment segmentNum=%d, libNum=%d, repeatCount=%d, transpose=%d",
- segmentNum, libNum, repeatCount, transpose);
- Mutex::Autolock lock(mMutex);
- return JET_QueueSegment(mEasData, segmentNum, libNum, repeatCount, transpose, muteFlags,
- userID);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::setMuteFlags(EAS_U32 muteFlags, bool sync)
-{
- Mutex::Autolock lock(mMutex);
- return JET_SetMuteFlags(mEasData, muteFlags, sync);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::setMuteFlag(int trackNum, bool muteFlag, bool sync)
-{
- Mutex::Autolock lock(mMutex);
- return JET_SetMuteFlag(mEasData, trackNum, muteFlag, sync);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::triggerClip(int clipId)
-{
- ALOGV("JetPlayer::triggerClip clipId=%d", clipId);
- Mutex::Autolock lock(mMutex);
- return JET_TriggerClip(mEasData, clipId);
-}
-
-//-------------------------------------------------------------------------------------------------
-int JetPlayer::clearQueue()
-{
- ALOGV("JetPlayer::clearQueue");
- Mutex::Autolock lock(mMutex);
- return JET_Clear_Queue(mEasData);
-}
-
-//-------------------------------------------------------------------------------------------------
-void JetPlayer::dump()
-{
-}
-
-void JetPlayer::dumpJetStatus(S_JET_STATUS* pJetStatus)
-{
- if (pJetStatus!=NULL)
- ALOGV(">> current JET player status: userID=%d segmentRepeatCount=%d numQueuedSegments=%d "
- "paused=%d",
- pJetStatus->currentUserID, pJetStatus->segmentRepeatCount,
- pJetStatus->numQueuedSegments, pJetStatus->paused);
- else
- ALOGE(">> JET player status is NULL");
-}
-
-
-} // end namespace android
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index d8ef9cf..6d46363 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -17,7 +17,6 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MidiIoWrapper"
#include <utils/Log.h>
-#include <utils/RefBase.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -50,7 +49,7 @@
mDataSource = nullptr;
}
-class DataSourceUnwrapper : public DataSourceBase {
+class DataSourceUnwrapper {
public:
explicit DataSourceUnwrapper(CDataSource *csource) {
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index cb8d375..2bf0802 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -77,10 +77,13 @@
if (t != 0) {
if (enabled) {
if (t->exitPending()) {
+ mCaptureLock.unlock();
if (t->requestExitAndWait() == WOULD_BLOCK) {
+ mCaptureLock.lock();
ALOGE("Visualizer::enable() called from thread");
return INVALID_OPERATION;
}
+ mCaptureLock.lock();
}
}
t->mLock.lock();
diff --git a/media/libmedia/include/media/IResourceManagerService.h b/media/libmedia/include/media/IResourceManagerService.h
index 1e4f6de..8992f8b 100644
--- a/media/libmedia/include/media/IResourceManagerService.h
+++ b/media/libmedia/include/media/IResourceManagerService.h
@@ -39,11 +39,15 @@
virtual void addResource(
int pid,
+ int uid,
int64_t clientId,
const sp<IResourceManagerClient> client,
const Vector<MediaResource> &resources) = 0;
- virtual void removeResource(int pid, int64_t clientId) = 0;
+ virtual void removeResource(int pid, int64_t clientId,
+ const Vector<MediaResource> &resources) = 0;
+
+ virtual void removeClient(int pid, int64_t clientId) = 0;
virtual bool reclaimResource(
int callingPid,
diff --git a/media/libmedia/include/media/JetPlayer.h b/media/libmedia/include/media/JetPlayer.h
deleted file mode 100644
index bb569bc..0000000
--- a/media/libmedia/include/media/JetPlayer.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2008 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 JETPLAYER_H_
-#define JETPLAYER_H_
-
-#include <utils/threads.h>
-
-#include <libsonivox/jet.h>
-#include <libsonivox/eas_types.h>
-#include <media/AudioTrack.h>
-#include <media/MidiIoWrapper.h>
-
-
-namespace android {
-
-typedef void (*jetevent_callback)(int eventType, int val1, int val2, void *cookie);
-
-class JetPlayer {
-
-public:
-
- // to keep in sync with the JetPlayer class constants
- // defined in frameworks/base/media/java/android/media/JetPlayer.java
- static const int JET_EVENT = 1;
- static const int JET_USERID_UPDATE = 2;
- static const int JET_NUMQUEUEDSEGMENT_UPDATE = 3;
- static const int JET_PAUSE_UPDATE = 4;
-
- JetPlayer(void *javaJetPlayer,
- int maxTracks = 32,
- int trackBufferSize = 1200);
- ~JetPlayer();
- int init();
- int release();
-
- int loadFromFile(const char* url);
- int loadFromFD(const int fd, const long long offset, const long long length);
- int closeFile();
- int play();
- int pause();
- int queueSegment(int segmentNum, int libNum, int repeatCount, int transpose,
- EAS_U32 muteFlags, EAS_U8 userID);
- int setMuteFlags(EAS_U32 muteFlags, bool sync);
- int setMuteFlag(int trackNum, bool muteFlag, bool sync);
- int triggerClip(int clipId);
- int clearQueue();
-
- void setEventCallback(jetevent_callback callback);
-
- int getMaxTracks() { return mMaxTracks; };
-
-
-private:
- int render();
- void fireUpdateOnStatusChange();
- void fireEventsFromJetQueue();
-
- JetPlayer() {} // no default constructor
- void dump();
- void dumpJetStatus(S_JET_STATUS* pJetStatus);
-
- jetevent_callback mEventCallback;
-
- void* mJavaJetPlayerRef;
- Mutex mMutex; // mutex to sync the render and playback thread with the JET calls
- pid_t mTid;
- Condition mCondition;
- volatile bool mRender;
- bool mPaused;
-
- EAS_STATE mState;
- int* mMemFailedVar;
-
- int mMaxTracks; // max number of MIDI tracks, usually 32
- EAS_DATA_HANDLE mEasData;
- MidiIoWrapper* mIoWrapper;
- EAS_PCM* mAudioBuffer;// EAS renders the MIDI data into this buffer,
- sp<AudioTrack> mAudioTrack; // and we play it in this audio track
- int mTrackBufferSize;
- S_JET_STATUS mJetStatus;
- S_JET_STATUS mPreviousJetStatus;
-
- class JetPlayerThread : public Thread {
- public:
- JetPlayerThread(JetPlayer *player) : mPlayer(player) {
- }
-
- protected:
- virtual ~JetPlayerThread() {}
-
- private:
- JetPlayer *mPlayer;
-
- bool threadLoop() {
- int result;
- result = mPlayer->render();
- return false;
- }
-
- JetPlayerThread(const JetPlayerThread &);
- JetPlayerThread &operator=(const JetPlayerThread &);
- };
-
- sp<JetPlayerThread> mThread;
-
-}; // end class JetPlayer
-
-} // end namespace android
-
-
-
-#endif /*JETPLAYER_H_*/
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index e1fdb9b..10a07bb 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -31,12 +31,13 @@
kNonSecureCodec,
kGraphicMemory,
kCpuBoost,
+ kBattery,
};
enum SubType {
kUnspecifiedSubType = 0,
kAudioCodec,
- kVideoCodec
+ kVideoCodec,
};
MediaResource();
@@ -62,6 +63,8 @@
case MediaResource::kSecureCodec: return "secure-codec";
case MediaResource::kNonSecureCodec: return "non-secure-codec";
case MediaResource::kGraphicMemory: return "graphic-memory";
+ case MediaResource::kCpuBoost: return "cpu-boost";
+ case MediaResource::kBattery: return "battery";
default: return def;
}
}
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 6709585..6701017 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -21,11 +21,13 @@
"libcodec2_client",
"libcrypto",
"libcutils",
+ "libdatasource",
"libdl",
"libgui",
"libhidlbase",
"liblog",
"libmedia",
+ "libmedia_codeclist",
"libmedia_omx",
"libmediadrm",
"libmediametrics",
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 1376ccc..05f7365 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -20,9 +20,9 @@
#include <utils/Log.h>
#include <cutils/properties.h>
+#include <datasource/FileSource.h>
#include <media/DataSource.h>
#include <media/IMediaPlayer.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#include <utils/Errors.h>
#include <utils/misc.h>
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index dfd3933..46c130f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -48,6 +48,7 @@
#include <utils/Vector.h>
#include <codec2/hidl/client.h>
+#include <datasource/HTTPBase.h>
#include <media/IMediaHTTPService.h>
#include <media/IRemoteDisplay.h>
#include <media/IRemoteDisplayClient.h>
@@ -61,6 +62,7 @@
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooperRoster.h>
#include <media/stagefright/SurfaceUtils.h>
@@ -80,7 +82,6 @@
#include "TestPlayerStub.h"
#include "nuplayer/NuPlayerDriver.h"
-#include "HTTPBase.h"
static const int kDumpLockRetries = 50;
static const int kDumpLockSleepUs = 20000;
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 49688ce..2562b8f 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -26,10 +26,12 @@
#include <utils/String8.h>
#include <utils/Vector.h>
+#include <media/AudioSystem.h>
#include <media/MediaPlayerInterface.h>
#include <media/Metadata.h>
#include <media/stagefright/foundation/ABase.h>
+
#include <system/audio.h>
namespace android {
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 40b17bf..4dbab0a 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -37,6 +37,7 @@
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <private/media/VideoFrame.h>
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.h"
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index 0ad4d04..436cb31 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -27,7 +27,6 @@
#include <media/mediaplayer.h>
#include <media/AudioResamplerPublic.h>
-#include <media/AudioSystem.h>
#include <media/AudioTimestamp.h>
#include <media/AVSyncSettings.h>
#include <media/BufferingSettings.h>
diff --git a/media/libmediaplayerservice/nuplayer/Android.bp b/media/libmediaplayerservice/nuplayer/Android.bp
index 71d8094..19c8e76 100644
--- a/media/libmediaplayerservice/nuplayer/Android.bp
+++ b/media/libmediaplayerservice/nuplayer/Android.bp
@@ -46,6 +46,7 @@
shared_libs: [
"libbinder",
+ "libdatasource",
"libui",
"libgui",
"libmedia",
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 4653711..e26f1e6 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -23,6 +23,10 @@
#include "AnotherPacketSource.h"
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
+#include <datasource/DataSourceFactory.h>
+#include <datasource/FileSource.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/NuCachedSource2.h>
#include <media/DataSource.h>
#include <media/MediaBufferHolder.h>
#include <media/MediaSource.h>
@@ -31,8 +35,6 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaClock.h>
@@ -41,8 +43,6 @@
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
-#include "../../libstagefright/include/NuCachedSource2.h"
-#include "../../libstagefright/include/HTTPBase.h"
namespace android {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 865cb2a..95c973a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -33,6 +33,7 @@
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/IMediaAnalyticsService.h>
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d198d39..369e13f 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1826,6 +1826,23 @@
mRepeatFrameDelayUs = -1LL;
}
+ if (!msg->findDouble("time-lapse-fps", &mCaptureFps)) {
+ float captureRate;
+ if (msg->findAsFloat(KEY_CAPTURE_RATE, &captureRate)) {
+ mCaptureFps = captureRate;
+ } else {
+ mCaptureFps = -1.0;
+ }
+ }
+
+ if (!msg->findInt32(
+ KEY_CREATE_INPUT_SURFACE_SUSPENDED,
+ (int32_t*)&mCreateInputBuffersSuspended)) {
+ mCreateInputBuffersSuspended = false;
+ }
+ }
+
+ if (encoder && (mIsVideo || mIsImage)) {
// only allow 32-bit value, since we pass it as U32 to OMX.
if (!msg->findInt64(KEY_MAX_PTS_GAP_TO_ENCODER, &mMaxPtsGapUs)) {
mMaxPtsGapUs = 0LL;
@@ -1842,16 +1859,6 @@
if (mMaxPtsGapUs < 0LL) {
mMaxFps = -1;
}
-
- if (!msg->findDouble("time-lapse-fps", &mCaptureFps)) {
- mCaptureFps = -1.0;
- }
-
- if (!msg->findInt32(
- KEY_CREATE_INPUT_SURFACE_SUSPENDED,
- (int32_t*)&mCreateInputBuffersSuspended)) {
- mCreateInputBuffersSuspended = false;
- }
}
// NOTE: we only use native window for video decoders
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 9c37b49..a6dbce3 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -19,8 +19,10 @@
],
cfi: true,
},
-
- shared_libs: ["libmedia"],
+ shared_libs: [
+ "libstagefright_foundation",
+ "libutils"
+ ],
}
cc_library_static {
@@ -65,7 +67,7 @@
shared_libs: [
"libgui",
"liblog",
- "libmedia_omx",
+ "libmedia_codeclist",
"libstagefright_foundation",
"libui",
"libutils",
@@ -125,7 +127,6 @@
"ACodecBufferChannel.cpp",
"AHierarchicalStateMachine.cpp",
"AMRWriter.cpp",
- "AudioPlayer.cpp",
"AudioSource.cpp",
"BufferImpl.cpp",
"CallbackDataSource.cpp",
@@ -133,13 +134,7 @@
"CameraSource.cpp",
"CameraSourceTimeLapse.cpp",
"DataConverter.cpp",
- "DataSourceBase.cpp",
- "DataSourceFactory.cpp",
- "DataURISource.cpp",
- "ClearFileSource.cpp",
- "FileSource.cpp",
"FrameDecoder.cpp",
- "HTTPBase.cpp",
"HevcUtils.cpp",
"InterfaceUtils.cpp",
"JPEGSource.cpp",
@@ -156,10 +151,7 @@
"MediaSource.cpp",
"MediaSync.cpp",
"MediaTrack.cpp",
- "http/ClearMediaHTTP.cpp",
- "http/MediaHTTP.cpp",
"MediaMuxer.cpp",
- "NuCachedSource2.cpp",
"NuMediaExtractor.cpp",
"OggWriter.cpp",
"OMXClient.cpp",
@@ -172,8 +164,8 @@
"StagefrightMetadataRetriever.cpp",
"StagefrightPluginLoader.cpp",
"SurfaceUtils.cpp",
- "Utils.cpp",
"ThrottledSource.cpp",
+ "Utils.cpp",
"VideoFrameSchedulerBase.cpp",
"VideoFrameScheduler.cpp",
],
@@ -184,12 +176,13 @@
"libbinder",
"libcamera_client",
"libcutils",
+ "libdatasource",
"libdl",
"libdl_android",
- "libdrmframework",
"libgui",
"liblog",
"libmedia",
+ "libmedia_codeclist",
"libmedia_omx",
"libmedia_omx_client",
"libaudioclient",
@@ -211,6 +204,7 @@
],
static_libs: [
+ "libstagefright_esds",
"libstagefright_color_conversion",
"libyuv_static",
"libstagefright_mediafilter",
@@ -218,9 +212,7 @@
"libstagefright_timedtext",
"libogg",
"libwebm",
- "libstagefright_esds",
"libstagefright_id3",
- "libFLAC",
],
header_libs:[
@@ -265,4 +257,3 @@
],
},
}
-
diff --git a/media/libstagefright/DataSourceBase.cpp b/media/libstagefright/DataSourceBase.cpp
deleted file mode 100644
index 8f47ee5..0000000
--- a/media/libstagefright/DataSourceBase.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2009 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 "DataSourceBase"
-
-#include <media/DataSourceBase.h>
-#include <media/stagefright/foundation/ByteUtils.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/String8.h>
-
-namespace android {
-
-bool DataSourceBase::getUInt16(off64_t offset, uint16_t *x) {
- *x = 0;
-
- uint8_t byte[2];
- if (readAt(offset, byte, 2) != 2) {
- return false;
- }
-
- *x = (byte[0] << 8) | byte[1];
-
- return true;
-}
-
-bool DataSourceBase::getUInt24(off64_t offset, uint32_t *x) {
- *x = 0;
-
- uint8_t byte[3];
- if (readAt(offset, byte, 3) != 3) {
- return false;
- }
-
- *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
-
- return true;
-}
-
-bool DataSourceBase::getUInt32(off64_t offset, uint32_t *x) {
- *x = 0;
-
- uint32_t tmp;
- if (readAt(offset, &tmp, 4) != 4) {
- return false;
- }
-
- *x = ntohl(tmp);
-
- return true;
-}
-
-bool DataSourceBase::getUInt64(off64_t offset, uint64_t *x) {
- *x = 0;
-
- uint64_t tmp;
- if (readAt(offset, &tmp, 8) != 8) {
- return false;
- }
-
- *x = ntoh64(tmp);
-
- return true;
-}
-
-bool DataSourceBase::getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
- if (size == 2) {
- return getUInt16(offset, x);
- }
- if (size == 1) {
- uint8_t tmp;
- if (readAt(offset, &tmp, 1) == 1) {
- *x = tmp;
- return true;
- }
- }
- return false;
-}
-
-bool DataSourceBase::getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
- if (size == 4) {
- return getUInt32(offset, x);
- }
- if (size == 2) {
- uint16_t tmp;
- if (getUInt16(offset, &tmp)) {
- *x = tmp;
- return true;
- }
- }
- return false;
-}
-
-bool DataSourceBase::getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
- if (size == 8) {
- return getUInt64(offset, x);
- }
- if (size == 4) {
- uint32_t tmp;
- if (getUInt32(offset, &tmp)) {
- *x = tmp;
- return true;
- }
- }
- return false;
-}
-
-status_t DataSourceBase::getSize(off64_t *size) {
- *size = 0;
-
- return ERROR_UNSUPPORTED;
-}
-
-bool DataSourceBase::getUri(char *uriString __unused, size_t bufferSize __unused) {
- return false;
-}
-
-} // namespace android
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 2f13dc9..f130c9b 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1635,8 +1635,13 @@
return BAD_VALUE;
}
+ // Increase moovExtraSize once only irrespective of how many times
+ // setCaptureRate is called.
+ bool containsCaptureFps = mMetaKeys->contains(kMetaKey_CaptureFps);
mMetaKeys->setFloat(kMetaKey_CaptureFps, captureFps);
- mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32;
+ if (!containsCaptureFps) {
+ mMoovExtraSize += sizeof(kMetaKey_CaptureFps) + 4 + 32;
+ }
return OK;
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 161c178..3d6ebc3 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -48,6 +48,7 @@
#include <media/stagefright/foundation/avc_utils.h>
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/ACodec.h>
+#include <media/stagefright/BatteryChecker.h>
#include <media/stagefright/BufferProducerWrapper.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/MediaCodecList.h>
@@ -57,7 +58,6 @@
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/PersistentSurface.h>
#include <media/stagefright/SurfaceUtils.h>
-#include <mediautils/BatteryNotifier.h>
#include <private/android_filesystem_config.h>
#include <utils/Singleton.h>
@@ -166,8 +166,9 @@
DISALLOW_EVIL_CONSTRUCTORS(ResourceManagerClient);
};
-MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(pid_t pid)
- : mPid(pid) {
+MediaCodec::ResourceManagerServiceProxy::ResourceManagerServiceProxy(
+ pid_t pid, uid_t uid)
+ : mPid(pid), mUid(uid) {
if (mPid == MediaCodec::kNoPid) {
mPid = IPCThreadState::self()->getCallingPid();
}
@@ -204,15 +205,25 @@
if (mService == NULL) {
return;
}
- mService->addResource(mPid, clientId, client, resources);
+ mService->addResource(mPid, mUid, clientId, client, resources);
}
-void MediaCodec::ResourceManagerServiceProxy::removeResource(int64_t clientId) {
+void MediaCodec::ResourceManagerServiceProxy::removeResource(
+ int64_t clientId,
+ const Vector<MediaResource> &resources) {
Mutex::Autolock _l(mLock);
if (mService == NULL) {
return;
}
- mService->removeResource(mPid, clientId);
+ mService->removeResource(mPid, clientId, resources);
+}
+
+void MediaCodec::ResourceManagerServiceProxy::removeClient(int64_t clientId) {
+ Mutex::Autolock _l(mLock);
+ if (mService == NULL) {
+ return;
+ }
+ mService->removeClient(mPid, clientId);
}
bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
@@ -517,9 +528,6 @@
mStickyError(OK),
mSoftRenderer(NULL),
mAnalyticsItem(NULL),
- mResourceManagerClient(new ResourceManagerClient(this)),
- mResourceManagerService(new ResourceManagerServiceProxy(pid)),
- mBatteryStatNotified(false),
mIsVideo(false),
mVideoWidth(0),
mVideoHeight(0),
@@ -537,13 +545,15 @@
} else {
mUid = uid;
}
+ mResourceManagerClient = new ResourceManagerClient(this);
+ mResourceManagerService = new ResourceManagerServiceProxy(pid, mUid);
initAnalyticsItem();
}
MediaCodec::~MediaCodec() {
CHECK_EQ(mState, UNINITIALIZED);
- mResourceManagerService->removeResource(getId(mResourceManagerClient));
+ mResourceManagerService->removeClient(getId(mResourceManagerClient));
flushAnalyticsItem();
}
@@ -742,6 +752,12 @@
return;
}
+ if (mBatteryChecker != nullptr) {
+ mBatteryChecker->onCodecActivity([this] () {
+ addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+ });
+ }
+
const int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
BufferFlightTiming_t startdata = { presentationUs, nowNs };
@@ -776,6 +792,12 @@
return;
}
+ if (mBatteryChecker != nullptr) {
+ mBatteryChecker->onCodecActivity([this] () {
+ addResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+ });
+ }
+
BufferFlightTiming_t startdata;
bool valid = false;
while (mBuffersInFlight.size() > 0) {
@@ -964,6 +986,10 @@
mAnalyticsItem->setCString(kCodecMode, mIsVideo ? kCodecModeVideo : kCodecModeAudio);
}
+ if (mIsVideo) {
+ mBatteryChecker = new BatteryChecker(new AMessage(kWhatCheckBatteryStats, this));
+ }
+
status_t err;
Vector<MediaResource> resources;
MediaResource::Type type =
@@ -1221,6 +1247,13 @@
getId(mResourceManagerClient), mResourceManagerClient, resources);
}
+void MediaCodec::removeResource(
+ MediaResource::Type type, MediaResource::SubType subtype, uint64_t value) {
+ Vector<MediaResource> resources;
+ resources.push_back(MediaResource(type, subtype, value));
+ mResourceManagerService->removeResource(getId(mResourceManagerClient), resources);
+}
+
status_t MediaCodec::start() {
sp<AMessage> msg = new AMessage(kWhatStart, this);
@@ -1682,6 +1715,59 @@
}
}
+BatteryChecker::BatteryChecker(const sp<AMessage> &msg, int64_t timeoutUs)
+ : mTimeoutUs(timeoutUs)
+ , mLastActivityTimeUs(-1ll)
+ , mBatteryStatNotified(false)
+ , mBatteryCheckerGeneration(0)
+ , mIsExecuting(false)
+ , mBatteryCheckerMsg(msg) {}
+
+void BatteryChecker::onCodecActivity(std::function<void()> batteryOnCb) {
+ if (!isExecuting()) {
+ // ignore if not executing
+ return;
+ }
+ if (!mBatteryStatNotified) {
+ batteryOnCb();
+ mBatteryStatNotified = true;
+ sp<AMessage> msg = mBatteryCheckerMsg->dup();
+ msg->setInt32("generation", mBatteryCheckerGeneration);
+
+ // post checker and clear last activity time
+ msg->post(mTimeoutUs);
+ mLastActivityTimeUs = -1ll;
+ } else {
+ // update last activity time
+ mLastActivityTimeUs = ALooper::GetNowUs();
+ }
+}
+
+void BatteryChecker::onCheckBatteryTimer(
+ const sp<AMessage> &msg, std::function<void()> batteryOffCb) {
+ // ignore if this checker already expired because the client resource was removed
+ int32_t generation;
+ if (!msg->findInt32("generation", &generation)
+ || generation != mBatteryCheckerGeneration) {
+ return;
+ }
+
+ if (mLastActivityTimeUs < 0ll) {
+ // timed out inactive, do not repost checker
+ batteryOffCb();
+ mBatteryStatNotified = false;
+ } else {
+ // repost checker and clear last activity time
+ msg->post(mTimeoutUs + mLastActivityTimeUs - ALooper::GetNowUs());
+ mLastActivityTimeUs = -1ll;
+ }
+}
+
+void BatteryChecker::onClientRemoved() {
+ mBatteryStatNotified = false;
+ mBatteryCheckerGeneration++;
+}
+
////////////////////////////////////////////////////////////////////////////////
void MediaCodec::cancelPendingDequeueOperations() {
@@ -2318,7 +2404,12 @@
mFlags &= ~kFlagIsComponentAllocated;
- mResourceManagerService->removeResource(getId(mResourceManagerClient));
+ // off since we're removing all resources including the battery on
+ if (mBatteryChecker != nullptr) {
+ mBatteryChecker->onClientRemoved();
+ }
+
+ mResourceManagerService->removeClient(getId(mResourceManagerClient));
(new AMessage)->postReply(mReplyID);
break;
@@ -3029,6 +3120,16 @@
break;
}
+ case kWhatCheckBatteryStats:
+ {
+ if (mBatteryChecker != nullptr) {
+ mBatteryChecker->onCheckBatteryTimer(msg, [this] () {
+ removeResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1);
+ });
+ }
+ break;
+ }
+
default:
TRESPASS();
}
@@ -3125,9 +3226,11 @@
mState = newState;
- cancelPendingDequeueOperations();
+ if (mBatteryChecker != nullptr) {
+ mBatteryChecker->setExecuting(isExecuting());
+ }
- updateBatteryStat();
+ cancelPendingDequeueOperations();
}
void MediaCodec::returnBuffersToCodec(bool isReclaim) {
@@ -3631,20 +3734,6 @@
return OK;
}
-void MediaCodec::updateBatteryStat() {
- if (!mIsVideo) {
- return;
- }
-
- if (mState == CONFIGURED && !mBatteryStatNotified) {
- BatteryNotifier::getInstance().noteStartVideo(mUid);
- mBatteryStatNotified = true;
- } else if (mState == UNINITIALIZED && mBatteryStatNotified) {
- BatteryNotifier::getInstance().noteStopVideo(mUid);
- mBatteryStatNotified = false;
- }
-}
-
std::string MediaCodec::stateString(State state) {
const char *rval = NULL;
char rawbuffer[16]; // room for "%d"
diff --git a/media/libstagefright/MediaMuxer.cpp b/media/libstagefright/MediaMuxer.cpp
index 9ba2add..7ebdb1a 100644
--- a/media/libstagefright/MediaMuxer.cpp
+++ b/media/libstagefright/MediaMuxer.cpp
@@ -96,10 +96,18 @@
sp<MediaAdapter> newTrack = new MediaAdapter(trackMeta);
status_t result = mWriter->addSource(newTrack);
- if (result == OK) {
- return mTrackList.add(newTrack);
+ if (result != OK) {
+ return -1;
}
- return -1;
+ float captureFps = -1.0;
+ if (format->findAsFloat("time-lapse-fps", &captureFps)) {
+ ALOGV("addTrack() time-lapse-fps: %f", captureFps);
+ result = mWriter->setCaptureRate(captureFps);
+ if (result != OK) {
+ ALOGW("addTrack() setCaptureRate failed :%d", result);
+ }
+ }
+ return mTrackList.add(newTrack);
}
status_t MediaMuxer::setOrientationHint(int degrees) {
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 680d426..b89dcdf 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -22,13 +22,13 @@
#include "include/ESDS.h"
+#include <datasource/DataSourceFactory.h>
+#include <datasource/FileSource.h>
#include <media/DataSource.h>
#include <media/MediaSource.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
@@ -36,6 +36,7 @@
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
namespace android {
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index fa3d372..c157ede 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -25,11 +25,11 @@
#include "include/FrameDecoder.h"
#include "include/StagefrightMetadataRetriever.h"
+#include <datasource/DataSourceFactory.h>
+#include <datasource/FileSource.h>
#include <media/IMediaHTTPService.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/DataSourceFactory.h>
-#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index 96818eb..c1b270c 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -7,6 +7,9 @@
"include-annotation": "android.platform.test.annotations.RequiresDevice"
}
]
+ },
+ {
+ "name": "BatteryChecker_test"
}
]
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 135151f..bda6053 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1895,22 +1895,6 @@
#endif
}
-AString MakeUserAgent() {
- AString ua;
- ua.append("stagefright/1.2 (Linux;Android ");
-
-#if (PROPERTY_VALUE_MAX < 8)
-#error "PROPERTY_VALUE_MAX must be at least 8"
-#endif
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.build.version.release", value, "Unknown");
- ua.append(value);
- ua.append(")");
-
- return ua;
-}
-
status_t sendMetaDataToHal(sp<MediaPlayerBase::AudioSink>& sink,
const sp<MetaData>& meta)
{
@@ -2099,39 +2083,6 @@
return AudioSystem::isOffloadSupported(info);
}
-AString uriDebugString(const AString &uri, bool incognito) {
- if (incognito) {
- return AString("<URI suppressed>");
- }
-
- if (property_get_bool("media.stagefright.log-uri", false)) {
- return uri;
- }
-
- // find scheme
- AString scheme;
- const char *chars = uri.c_str();
- for (size_t i = 0; i < uri.size(); i++) {
- const char c = chars[i];
- if (!isascii(c)) {
- break;
- } else if (isalpha(c)) {
- continue;
- } else if (i == 0) {
- // first character must be a letter
- break;
- } else if (isdigit(c) || c == '+' || c == '.' || c =='-') {
- continue;
- } else if (c != ':') {
- break;
- }
- scheme = AString(uri, 0, i);
- scheme.append("://<suppressed>");
- return scheme;
- }
- return AString("<no-scheme URI suppressed>");
-}
-
HLSTime::HLSTime(const sp<AMessage>& meta) :
mSeq(-1),
mTimeUs(-1LL),
@@ -2230,36 +2181,4 @@
}
}
-AString nameForFd(int fd) {
- const size_t SIZE = 256;
- char buffer[SIZE];
- AString result;
- snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
- struct stat s;
- if (lstat(buffer, &s) == 0) {
- if ((s.st_mode & S_IFMT) == S_IFLNK) {
- char linkto[256];
- int len = readlink(buffer, linkto, sizeof(linkto));
- if(len > 0) {
- if(len > 255) {
- linkto[252] = '.';
- linkto[253] = '.';
- linkto[254] = '.';
- linkto[255] = 0;
- } else {
- linkto[len] = 0;
- }
- result.append(linkto);
- }
- } else {
- result.append("unexpected type for ");
- result.append(buffer);
- }
- } else {
- result.append("couldn't open ");
- result.append(buffer);
- }
- return result;
-}
-
} // namespace android
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
index f18f789..679b091 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
@@ -1355,6 +1355,14 @@
int tmpHeight = (tmpDisplayHeight + 15) & -16;
int tmpWidth = (tmpDisplayWidth + 15) & -16;
+ if (tmpWidth > video->width)
+ {
+ // while allowed by the spec, this decoder does not actually
+ // support an increase in size.
+ ALOGE("width increase not supported");
+ status = PV_FAIL;
+ goto return_point;
+ }
if (tmpHeight * tmpWidth > video->size)
{
// This is just possibly "b/37079296".
diff --git a/media/libstagefright/foundation/Android.bp b/media/libstagefright/foundation/Android.bp
index 533cd72..b95f054 100644
--- a/media/libstagefright/foundation/Android.bp
+++ b/media/libstagefright/foundation/Android.bp
@@ -65,6 +65,7 @@
"AudioPresentationInfo.cpp",
"ByteUtils.cpp",
"ColorUtils.cpp",
+ "FoundationUtils.cpp",
"MediaBuffer.cpp",
"MediaBufferBase.cpp",
"MediaBufferGroup.cpp",
diff --git a/media/libstagefright/foundation/FoundationUtils.cpp b/media/libstagefright/foundation/FoundationUtils.cpp
new file mode 100644
index 0000000..8285e4c
--- /dev/null
+++ b/media/libstagefright/foundation/FoundationUtils.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2009 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 "FoundationUtils"
+#include <utils/Log.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+AString uriDebugString(const AString &uri, bool incognito) {
+ if (incognito) {
+ return AString("<URI suppressed>");
+ }
+
+ if (property_get_bool("media.stagefright.log-uri", false)) {
+ return uri;
+ }
+
+ // find scheme
+ AString scheme;
+ const char *chars = uri.c_str();
+ for (size_t i = 0; i < uri.size(); i++) {
+ const char c = chars[i];
+ if (!isascii(c)) {
+ break;
+ } else if (isalpha(c)) {
+ continue;
+ } else if (i == 0) {
+ // first character must be a letter
+ break;
+ } else if (isdigit(c) || c == '+' || c == '.' || c =='-') {
+ continue;
+ } else if (c != ':') {
+ break;
+ }
+ scheme = AString(uri, 0, i);
+ scheme.append("://<suppressed>");
+ return scheme;
+ }
+ return AString("<no-scheme URI suppressed>");
+}
+
+AString MakeUserAgent() {
+ AString ua;
+ ua.append("stagefright/1.2 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.version.release", value, "Unknown");
+ ua.append(value);
+ ua.append(")");
+
+ return ua;
+}
+
+AString nameForFd(int fd) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ AString result;
+ snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
+ struct stat s;
+ if (lstat(buffer, &s) == 0) {
+ if ((s.st_mode & S_IFMT) == S_IFLNK) {
+ char linkto[256];
+ int len = readlink(buffer, linkto, sizeof(linkto));
+ if(len > 0) {
+ if(len > 255) {
+ linkto[252] = '.';
+ linkto[253] = '.';
+ linkto[254] = '.';
+ linkto[255] = 0;
+ } else {
+ linkto[len] = 0;
+ }
+ result.append(linkto);
+ }
+ } else {
+ result.append("unexpected type for ");
+ result.append(buffer);
+ }
+ } else {
+ result.append("couldn't open ");
+ result.append(buffer);
+ }
+ return result;
+}
+
+} // namespace android
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index c0ee14e..12e7ca6 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -31,6 +31,7 @@
"liblog",
"libcrypto",
"libcutils",
+ "libdatasource",
"libmedia",
"libmediandk",
"libstagefright",
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index c7e92cd..7183dbd 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -21,13 +21,13 @@
#include "HTTPDownloader.h"
#include "M3UParser.h"
+#include <datasource/ClearMediaHTTP.h>
+#include <datasource/ClearFileSource.h>
#include <media/DataSource.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ClearMediaHTTP.h>
-#include <media/stagefright/ClearFileSource.h>
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <utils/Mutex.h>
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 9cf97c7..3bad015 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -34,6 +34,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <utils/Mutex.h>
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index cb97a3c..e0324e3 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -27,6 +27,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <media/mediaplayer.h>
namespace android {
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 635ecfe..4d0848a 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -28,17 +28,18 @@
#include "mpeg2ts/AnotherPacketSource.h"
#include "mpeg2ts/HlsSampleDecryptor.h"
+#include <datasource/DataURISource.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ByteUtils.h>
#include <media/stagefright/foundation/MediaKeys.h>
#include <media/stagefright/foundation/avc_utils.h>
-#include <media/stagefright/DataURISource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaDataUtils.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <ctype.h>
#include <inttypes.h>
diff --git a/media/libstagefright/id3/Android.bp b/media/libstagefright/id3/Android.bp
index 7151d07..d9704a6 100644
--- a/media/libstagefright/id3/Android.bp
+++ b/media/libstagefright/id3/Android.bp
@@ -33,6 +33,7 @@
],
shared_libs: [
+ "libdatasource",
"libstagefright",
"libutils",
"liblog",
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 86e6adf..9984d85 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -22,7 +22,7 @@
#include <dirent.h>
#include <binder/ProcessState.h>
-#include <media/stagefright/FileSource.h>
+#include <datasource/FileSource.h>
#include <media/stagefright/foundation/ADebug.h>
#define MAXPATHLEN 256
diff --git a/media/libstagefright/include/media/stagefright/BatteryChecker.h b/media/libstagefright/include/media/stagefright/BatteryChecker.h
new file mode 100644
index 0000000..2ec4ac0
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/BatteryChecker.h
@@ -0,0 +1,47 @@
+/*
+ * 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 BATTERY_CHECKER_H_
+#define BATTERY_CHECKER_H_
+
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+
+struct BatteryChecker : public RefBase {
+ BatteryChecker(const sp<AMessage> &msg, int64_t timeout = 3000000ll);
+
+ void setExecuting(bool executing) { mIsExecuting = executing; }
+ void onCodecActivity(std::function<void()> batteryOnCb);
+ void onCheckBatteryTimer(const sp<AMessage>& msg, std::function<void()> batteryOffCb);
+ void onClientRemoved();
+
+private:
+ const int64_t mTimeoutUs;
+ int64_t mLastActivityTimeUs;
+ bool mBatteryStatNotified;
+ int32_t mBatteryCheckerGeneration;
+ bool mIsExecuting;
+ sp<AMessage> mBatteryCheckerMsg;
+
+ bool isExecuting() { return mIsExecuting; }
+
+ DISALLOW_EVIL_CONSTRUCTORS(BatteryChecker);
+};
+
+} // namespace android
+
+#endif // BATTERY_CHECKER_H_
diff --git a/media/libstagefright/include/media/stagefright/DataSourceBase.h b/media/libstagefright/include/media/stagefright/DataSourceBase.h
index af5b83d..c607c91 100644
--- a/media/libstagefright/include/media/stagefright/DataSourceBase.h
+++ b/media/libstagefright/include/media/stagefright/DataSourceBase.h
@@ -18,6 +18,8 @@
#define DATA_SOURCE_BASE_H_
+#include <media/stagefright/foundation/ByteUtils.h>
+#include <media/stagefright/MediaErrors.h>
#include <sys/types.h>
#include <utils/Errors.h>
@@ -45,20 +47,106 @@
virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0;
// Convenience methods:
- bool getUInt16(off64_t offset, uint16_t *x);
- bool getUInt24(off64_t offset, uint32_t *x); // 3 byte int, returned as a 32-bit int
- bool getUInt32(off64_t offset, uint32_t *x);
- bool getUInt64(off64_t offset, uint64_t *x);
+ bool getUInt16(off64_t offset, uint16_t *x) {
+ *x = 0;
+
+ uint8_t byte[2];
+ if (readAt(offset, byte, 2) != 2) {
+ return false;
+ }
+
+ *x = (byte[0] << 8) | byte[1];
+
+ return true;
+ }
+ // 3 byte int, returned as a 32-bit int
+ bool getUInt24(off64_t offset, uint32_t *x) {
+ *x = 0;
+
+ uint8_t byte[3];
+ if (readAt(offset, byte, 3) != 3) {
+ return false;
+ }
+
+ *x = (byte[0] << 16) | (byte[1] << 8) | byte[2];
+
+ return true;
+ }
+ bool getUInt32(off64_t offset, uint32_t *x) {
+ *x = 0;
+
+ uint32_t tmp;
+ if (readAt(offset, &tmp, 4) != 4) {
+ return false;
+ }
+
+ *x = ntohl(tmp);
+
+ return true;
+ }
+ bool getUInt64(off64_t offset, uint64_t *x) {
+ *x = 0;
+
+ uint64_t tmp;
+ if (readAt(offset, &tmp, 8) != 8) {
+ return false;
+ }
+
+ *x = ntoh64(tmp);
+
+ return true;
+ }
// read either int<N> or int<2N> into a uint<2N>_t, size is the int size in bytes.
- bool getUInt16Var(off64_t offset, uint16_t *x, size_t size);
- bool getUInt32Var(off64_t offset, uint32_t *x, size_t size);
- bool getUInt64Var(off64_t offset, uint64_t *x, size_t size);
+ bool getUInt16Var(off64_t offset, uint16_t *x, size_t size) {
+ if (size == 2) {
+ return getUInt16(offset, x);
+ }
+ if (size == 1) {
+ uint8_t tmp;
+ if (readAt(offset, &tmp, 1) == 1) {
+ *x = tmp;
+ return true;
+ }
+ }
+ return false;
+ }
+ bool getUInt32Var(off64_t offset, uint32_t *x, size_t size) {
+ if (size == 4) {
+ return getUInt32(offset, x);
+ }
+ if (size == 2) {
+ uint16_t tmp;
+ if (getUInt16(offset, &tmp)) {
+ *x = tmp;
+ return true;
+ }
+ }
+ return false;
+ }
+ bool getUInt64Var(off64_t offset, uint64_t *x, size_t size) {
+ if (size == 8) {
+ return getUInt64(offset, x);
+ }
+ if (size == 4) {
+ uint32_t tmp;
+ if (getUInt32(offset, &tmp)) {
+ *x = tmp;
+ return true;
+ }
+ }
+ return false;
+ }
// May return ERROR_UNSUPPORTED.
- virtual status_t getSize(off64_t *size);
+ virtual status_t getSize(off64_t *size) {
+ *size = 0;
+ return ERROR_UNSUPPORTED;
+ }
- virtual bool getUri(char *uriString, size_t bufferSize);
+ virtual bool getUri(char * /*uriString*/, size_t /*bufferSize*/) {
+ return false;
+ }
virtual uint32_t flags() {
return 0;
diff --git a/media/libstagefright/include/media/stagefright/FoundationUtils.h b/media/libstagefright/include/media/stagefright/FoundationUtils.h
new file mode 100644
index 0000000..1548981
--- /dev/null
+++ b/media/libstagefright/include/media/stagefright/FoundationUtils.h
@@ -0,0 +1,32 @@
+/*
+ * 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 FOUNDATION_UTILS_H_
+
+#define FOUNDATION_UTILS_H_
+
+#include <media/stagefright/foundation/AString.h>
+
+namespace android {
+
+AString MakeUserAgent();
+
+AString uriDebugString(const AString &uri, bool incognito = false);
+
+AString nameForFd(int fd);
+} // namespace android
+
+#endif // FOUNDATION_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 89cca63..cd30347 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -36,6 +36,7 @@
struct AMessage;
struct AReplyToken;
struct AString;
+struct BatteryChecker;
class BufferChannelBase;
struct CodecBase;
class IBatteryStats;
@@ -257,6 +258,7 @@
kWhatSetCallback = 'setC',
kWhatSetNotification = 'setN',
kWhatDrmReleaseCrypto = 'rDrm',
+ kWhatCheckBatteryStats = 'chkB',
};
enum {
@@ -283,7 +285,7 @@
};
struct ResourceManagerServiceProxy : public IBinder::DeathRecipient {
- ResourceManagerServiceProxy(pid_t pid);
+ ResourceManagerServiceProxy(pid_t pid, uid_t uid);
~ResourceManagerServiceProxy();
void init();
@@ -296,7 +298,11 @@
const sp<IResourceManagerClient> &client,
const Vector<MediaResource> &resources);
- void removeResource(int64_t clientId);
+ void removeResource(
+ int64_t clientId,
+ const Vector<MediaResource> &resources);
+
+ void removeClient(int64_t clientId);
bool reclaimResource(const Vector<MediaResource> &resources);
@@ -304,6 +310,7 @@
Mutex mLock;
sp<IResourceManagerService> mService;
pid_t mPid;
+ uid_t mUid;
};
State mState;
@@ -335,7 +342,6 @@
sp<IResourceManagerClient> mResourceManagerClient;
sp<ResourceManagerServiceProxy> mResourceManagerService;
- bool mBatteryStatNotified;
bool mIsVideo;
int32_t mVideoWidth;
int32_t mVideoHeight;
@@ -425,11 +431,11 @@
status_t onSetParameters(const sp<AMessage> ¶ms);
status_t amendOutputFormatWithCodecSpecificData(const sp<MediaCodecBuffer> &buffer);
- void updateBatteryStat();
bool isExecuting() const;
uint64_t getGraphicBufferSize();
void addResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
+ void removeResource(MediaResource::Type type, MediaResource::SubType subtype, uint64_t value);
void requestCpuBoostIfNeeded();
bool hasPendingBuffer(int portIndex);
@@ -458,6 +464,8 @@
Mutex mLatencyLock;
int64_t mLatencyUnknown; // buffers for which we couldn't calculate latency
+ sp<BatteryChecker> mBatteryChecker;
+
void statsBufferSent(int64_t presentationUs);
void statsBufferReceived(int64_t presentationUs);
diff --git a/media/libstagefright/include/media/stagefright/MediaWriter.h b/media/libstagefright/include/media/stagefright/MediaWriter.h
index 2c12a87..972ae1d 100644
--- a/media/libstagefright/include/media/stagefright/MediaWriter.h
+++ b/media/libstagefright/include/media/stagefright/MediaWriter.h
@@ -35,6 +35,10 @@
virtual status_t start(MetaData *params = NULL) = 0;
virtual status_t stop() = 0;
virtual status_t pause() = 0;
+ virtual status_t setCaptureRate(float /* captureFps */) {
+ ALOGW("setCaptureRate unsupported");
+ return ERROR_UNSUPPORTED;
+ }
virtual void setMaxFileSize(int64_t bytes) { mMaxFileSizeLimitBytes = bytes; }
virtual void setMaxFileDuration(int64_t durationUs) { mMaxFileDurationLimitUs = durationUs; }
diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
index e8e0a11..2b9b759 100644
--- a/media/libstagefright/include/media/stagefright/Utils.h
+++ b/media/libstagefright/include/media/stagefright/Utils.h
@@ -41,8 +41,6 @@
// TODO: combine this with avc_utils::getNextNALUnit
const uint8_t *findNextNalStartCode(const uint8_t *data, size_t length);
-AString MakeUserAgent();
-
// Convert a MIME type to a AudioSystem::audio_format
status_t mapMimeToAudioFormat(audio_format_t& format, const char* mime);
@@ -60,8 +58,6 @@
bool canOffloadStream(const sp<MetaData>& meta, bool hasVideo,
bool isStreaming, audio_stream_type_t streamType);
-AString uriDebugString(const AString &uri, bool incognito = false);
-
struct HLSTime {
int32_t mSeq;
int64_t mTimeUs;
@@ -85,7 +81,6 @@
void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering);
void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */);
-AString nameForFd(int fd);
} // namespace android
#endif // UTILS_H_
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index 569fa88..eb01543 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -7,6 +7,7 @@
shared_libs: [
"libstagefright",
"libbinder",
+ "libdatasource",
"libmedia",
"libmedia_omx",
"libutils",
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index cc8c234..ee01d6c 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -27,13 +27,13 @@
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaSource.h>
#include <media/OMXBuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaDefs.h>
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 789e62a..cac1af9 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -21,12 +21,14 @@
#include "ARTSPConnection.h"
#include "NetworkUtils.h"
+#include <datasource/HTTPBase.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <arpa/inet.h>
#include <fcntl.h>
@@ -34,7 +36,6 @@
#include <openssl/md5.h>
#include <sys/socket.h>
-#include "include/HTTPBase.h"
namespace android {
diff --git a/media/libstagefright/rtsp/Android.bp b/media/libstagefright/rtsp/Android.bp
index 9bc9c89..a5a895e 100644
--- a/media/libstagefright/rtsp/Android.bp
+++ b/media/libstagefright/rtsp/Android.bp
@@ -21,6 +21,7 @@
shared_libs: [
"libcrypto",
+ "libdatasource",
"libmedia",
],
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 48bc8ce..9c30623 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -36,18 +36,19 @@
#include <ctype.h>
#include <cutils/properties.h>
+#include <datasource/HTTPBase.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
-#include "HTTPBase.h"
#if LOG_NDEBUG
#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index 665d51a..5bd218d 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -22,12 +22,13 @@
#include "ASessionDescription.h"
+#include <datasource/ClearMediaHTTP.h>
#include <media/MediaHTTPConnection.h>
#include <media/MediaHTTPService.h>
-#include <media/stagefright/ClearMediaHTTP.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
+#include <media/stagefright/FoundationUtils.h>
#define DEFAULT_SDP_SIZE 100000
diff --git a/media/libstagefright/tests/Android.bp b/media/libstagefright/tests/Android.bp
index be10fdc..a7f94c1 100644
--- a/media/libstagefright/tests/Android.bp
+++ b/media/libstagefright/tests/Android.bp
@@ -27,3 +27,21 @@
"-Wall",
],
}
+
+cc_test {
+ name: "BatteryChecker_test",
+ srcs: ["BatteryChecker_test.cpp"],
+ test_suites: ["device-tests"],
+
+ shared_libs: [
+ "libstagefright",
+ "libstagefright_foundation",
+ "libutils",
+ "liblog",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
\ No newline at end of file
diff --git a/media/libstagefright/tests/BatteryChecker_test.cpp b/media/libstagefright/tests/BatteryChecker_test.cpp
new file mode 100644
index 0000000..0c5ee9b
--- /dev/null
+++ b/media/libstagefright/tests/BatteryChecker_test.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "BatteryChecker_test"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include <media/stagefright/BatteryChecker.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AHandler.h>
+
+#include <vector>
+
+namespace android {
+
+static const int kBatteryTimeoutUs = 1000000ll; // 1 seconds
+static const int kTestMarginUs = 50000ll; // 50ms
+static const int kWaitStatusChangeUs = kBatteryTimeoutUs + kTestMarginUs;
+static const int kSparseFrameIntervalUs = kBatteryTimeoutUs - kTestMarginUs;
+
+class BatteryCheckerTestHandler : public AHandler {
+ enum EventType {
+ // Events simulating MediaCodec
+ kWhatStart = 0, // codec entering executing state
+ kWhatStop, // codec exiting executing state
+ kWhatActivity, // codec queue input or dequeue output
+ kWhatReleased, // codec released
+ kWhatCheckpoint, // test checkpoing with expected values on On/Off
+
+ // Message for battery checker monitor (not for testing through runTest())
+ kWhatBatteryChecker,
+ };
+
+ struct Operation {
+ int32_t event;
+ int64_t delay = 0;
+ uint32_t repeatCount = 0;
+ int32_t expectedOnCounter = 0;
+ int32_t expectedOffCounter = 0;
+ };
+
+ std::vector<Operation> mOps;
+ sp<BatteryChecker> mBatteryChecker;
+ int32_t mOnCounter;
+ int32_t mOffCounter;
+ Condition mDone;
+ Mutex mLock;
+
+ BatteryCheckerTestHandler() : mOnCounter(0), mOffCounter(0) {}
+
+ void runTest(const std::vector<Operation> &ops, int64_t timeoutUs) {
+ mOps = ops;
+
+ mBatteryChecker = new BatteryChecker(
+ new AMessage(kWhatBatteryChecker, this), kBatteryTimeoutUs);
+
+ (new AMessage(ops[0].event, this))->post();
+
+ // wait for done
+ AutoMutex lock(mLock);
+ EXPECT_NE(TIMED_OUT, mDone.waitRelative(mLock, timeoutUs * 1000ll));
+ }
+
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
+ friend class BatteryCheckerTest;
+};
+
+class BatteryCheckerTest : public ::testing::Test {
+public:
+ BatteryCheckerTest()
+ : mLooper(new ALooper)
+ , mHandler(new BatteryCheckerTestHandler()) {
+ mLooper->setName("BatterCheckerLooper");
+ mLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+ mLooper->registerHandler(mHandler);
+ }
+
+protected:
+ using EventType = BatteryCheckerTestHandler::EventType;
+ using Operation = BatteryCheckerTestHandler::Operation;
+
+ virtual ~BatteryCheckerTest() {
+ mLooper->stop();
+ mLooper->unregisterHandler(mHandler->id());
+ }
+
+ void runTest(const std::vector<Operation> &ops, int64_t timeoutUs) {
+ mHandler->runTest(ops, timeoutUs);
+ }
+
+ sp<ALooper> mLooper;
+ sp<BatteryCheckerTestHandler> mHandler;
+};
+
+void BatteryCheckerTestHandler::onMessageReceived(const sp<AMessage> &msg) {
+ switch(msg->what()) {
+ case kWhatStart:
+ mBatteryChecker->setExecuting(true);
+ break;
+ case kWhatStop:
+ mBatteryChecker->setExecuting(false);
+ break;
+ case kWhatActivity:
+ mBatteryChecker->onCodecActivity([this] () { mOnCounter++; });
+ break;
+ case kWhatReleased:
+ mBatteryChecker->onClientRemoved();
+ break;
+ case kWhatBatteryChecker:
+ mBatteryChecker->onCheckBatteryTimer(msg, [this] () { mOffCounter++; });
+ break;
+ case kWhatCheckpoint:
+ // verify ON/OFF state and total events
+ EXPECT_EQ(mOnCounter, mOps[0].expectedOnCounter);
+ EXPECT_EQ(mOffCounter, mOps[0].expectedOffCounter);
+ break;
+ default:
+ TRESPASS();
+ }
+ if (msg->what() != kWhatBatteryChecker) {
+ EXPECT_EQ(msg->what(), mOps[0].event);
+ // post next message
+ if (!mOps[0].repeatCount) {
+ mOps.erase(mOps.begin());
+ } else {
+ mOps[0].repeatCount--;
+ }
+ int64_t duration = mOps[0].delay;
+ if (!mOps.empty()) {
+ (new AMessage(mOps[0].event, this))->post(duration);
+ } else {
+ AutoMutex lock(mLock);
+ mDone.signal();
+ }
+ }
+}
+
+TEST_F(BatteryCheckerTest, testNormalOperations) {
+ runTest({
+ {EventType::kWhatStart, 0ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 0, 0},
+ {EventType::kWhatActivity, 33333ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 0}, // ON
+ {EventType::kWhatActivity, 33333ll, 2*kWaitStatusChangeUs/33333ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 0},
+ {EventType::kWhatCheckpoint, kWaitStatusChangeUs, 0, 1, 1}, // OFF
+ }, 10000000ll);
+}
+
+TEST_F(BatteryCheckerTest, testPauseResume) {
+ runTest({
+ {EventType::kWhatStart, 0ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 0, 0},
+ {EventType::kWhatActivity, 33333ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 0}, // ON
+ {EventType::kWhatCheckpoint, kWaitStatusChangeUs, 0, 1, 1}, // OFF
+ {EventType::kWhatActivity, 33333ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 2, 1}, // ON
+ {EventType::kWhatCheckpoint, kWaitStatusChangeUs, 0, 2, 2}, // OFF
+ }, 10000000ll);
+}
+
+TEST_F(BatteryCheckerTest, testClientRemovedAndRestart) {
+ runTest({
+ {EventType::kWhatStart, 0ll},
+ {EventType::kWhatActivity, 33333ll, kWaitStatusChangeUs/33333ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 0},
+
+ // stop executing state itself shouldn't trigger any calls
+ {EventType::kWhatStop, 0ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 0},
+
+ // release shouldn't trigger any calls either,
+ // client resource will be removed entirely
+ {EventType::kWhatReleased, 0ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 0},
+ {EventType::kWhatCheckpoint, kWaitStatusChangeUs, 0, 1, 0},
+
+ // start pushing buffers again, On should be received without any Off
+ {EventType::kWhatStart, 0ll},
+ {EventType::kWhatActivity, 33333ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 2, 0},
+
+ // double check that only new checker msg triggers OFF,
+ // left-over checker msg from stale generate discarded
+ {EventType::kWhatCheckpoint, kWaitStatusChangeUs, 0, 2, 1},
+ }, 10000000ll);
+}
+
+TEST_F(BatteryCheckerTest, testActivityWhileNotExecuting) {
+ runTest({
+ // activity before start shouldn't trigger
+ {EventType::kWhatActivity, 0ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 0, 0},
+
+ {EventType::kWhatStart, 0ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 0, 0},
+
+ // activity after start before stop should trigger
+ {EventType::kWhatActivity, 33333ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 0},
+
+ // stop executing state itself shouldn't trigger any calls
+ {EventType::kWhatStop, 0ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 0},
+
+ // keep pushing another 3 seconds after stop, expected to OFF
+ {EventType::kWhatActivity, 33333ll, kWaitStatusChangeUs/33333ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 1},
+ }, 10000000ll);
+}
+
+TEST_F(BatteryCheckerTest, testSparseActivity) {
+ runTest({
+ {EventType::kWhatStart, 0ll},
+ {EventType::kWhatCheckpoint, 0ll, 0, 0, 0},
+
+ // activity arrives sparsely with interval only slightly small than timeout
+ // should only trigger 1 ON
+ {EventType::kWhatActivity, kSparseFrameIntervalUs, 2},
+ {EventType::kWhatCheckpoint, 0ll, 0, 1, 0},
+ {EventType::kWhatCheckpoint, kSparseFrameIntervalUs, 0, 1, 0},
+ {EventType::kWhatCheckpoint, kTestMarginUs, 0, 1, 1}, // OFF
+ }, 10000000ll);
+}
+} // namespace android
diff --git a/media/libstagefright/webm/Android.bp b/media/libstagefright/webm/Android.bp
index 64ecc2d..9f3e807 100644
--- a/media/libstagefright/webm/Android.bp
+++ b/media/libstagefright/webm/Android.bp
@@ -27,6 +27,7 @@
include_dirs: ["frameworks/av/include"],
shared_libs: [
+ "libdatasource",
"libstagefright_foundation",
"libutils",
"liblog",
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
index 1ddaf9a..2dde20a 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -20,8 +20,8 @@
#include "WebmFrame.h"
#include "LinkedBlockingQueue.h"
+#include <datasource/FileSource.h>
#include <media/MediaSource.h>
-#include <media/stagefright/FileSource.h>
#include <utils/List.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/xmlparser/api/current.txt b/media/libstagefright/xmlparser/api/current.txt
index 9d7c57d..16c8af8 100644
--- a/media/libstagefright/xmlparser/api/current.txt
+++ b/media/libstagefright/xmlparser/api/current.txt
@@ -138,7 +138,12 @@
public class Variant {
ctor public Variant();
+ method public java.util.List<media.codecs.Alias> getAlias_optional();
+ method public java.util.List<media.codecs.Quirk> getAttribute_optional();
+ method public java.util.List<media.codecs.Feature> getFeature_optional();
+ method public java.util.List<media.codecs.Limit> getLimit_optional();
method public String getName();
+ method public java.util.List<media.codecs.Quirk> getQuirk_optional();
method public void setName(String);
}
diff --git a/media/libstagefright/xmlparser/media_codecs.xsd b/media/libstagefright/xmlparser/media_codecs.xsd
index 63ec5d0..3b5681f 100644
--- a/media/libstagefright/xmlparser/media_codecs.xsd
+++ b/media/libstagefright/xmlparser/media_codecs.xsd
@@ -107,6 +107,13 @@
<xs:attribute name="value" type="xs:string"/>
</xs:complexType>
<xs:complexType name="Variant">
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="Quirk" type="Quirk"/>
+ <xs:element name="Attribute" type="Quirk"/>
+ <xs:element name="Alias" type="Alias"/>
+ <xs:element name="Limit" type="Limit"/>
+ <xs:element name="Feature" type="Feature"/>
+ </xs:choice>
<xs:attribute name="name" type="xs:string"/>
</xs:complexType>
<xs:complexType name="Setting">
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 0020ccc..61f9014 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -79,6 +79,7 @@
"libandroid_runtime_lazy",
"libbase",
"libbinder",
+ "libdatasource",
"libmedia",
"libmediadrm",
"libmedia_omx",
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 1883f63..1145b7b 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -35,6 +35,7 @@
int64_t timestamp, int32_t width, int32_t height, int32_t numPlanes) :
mReader(reader), mFormat(format), mUsage(usage), mBuffer(buffer), mLockedBuffer(nullptr),
mTimestamp(timestamp), mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
+ LOG_FATAL_IF(reader == nullptr, "AImageReader shouldn't be null while creating AImage");
}
AImage::~AImage() {
@@ -57,14 +58,9 @@
if (mIsClosed) {
return;
}
- sp<AImageReader> reader = mReader.promote();
- if (reader != nullptr) {
- reader->releaseImageLocked(this, releaseFenceFd);
- } else if (mBuffer != nullptr) {
- LOG_ALWAYS_FATAL("%s: parent AImageReader closed without releasing image %p",
- __FUNCTION__, this);
+ if (!mReader->mIsClosed) {
+ mReader->releaseImageLocked(this, releaseFenceFd);
}
-
// Should have been set to nullptr in releaseImageLocked
// Set to nullptr here for extra safety only
mBuffer = nullptr;
@@ -83,22 +79,12 @@
void
AImage::lockReader() const {
- sp<AImageReader> reader = mReader.promote();
- if (reader == nullptr) {
- // Reader has been closed
- return;
- }
- reader->mLock.lock();
+ mReader->mLock.lock();
}
void
AImage::unlockReader() const {
- sp<AImageReader> reader = mReader.promote();
- if (reader == nullptr) {
- // Reader has been closed
- return;
- }
- reader->mLock.unlock();
+ mReader->mLock.unlock();
}
media_status_t
diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h
index e0f16da..0e8cbcb 100644
--- a/media/ndk/NdkImagePriv.h
+++ b/media/ndk/NdkImagePriv.h
@@ -72,7 +72,7 @@
uint32_t getJpegSize() const;
// When reader is close, AImage will only accept close API call
- wp<AImageReader> mReader;
+ const sp<AImageReader> mReader;
const int32_t mFormat;
const uint64_t mUsage; // AHARDWAREBUFFER_USAGE_* flags.
BufferItem* mBuffer;
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index baa4fc7..c0ceb3d 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -113,12 +113,12 @@
void
AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
- Mutex::Autolock _l(mLock);
sp<AImageReader> reader = mReader.promote();
if (reader == nullptr) {
ALOGW("A frame is available after AImageReader closed!");
return; // reader has been closed
}
+ Mutex::Autolock _l(mLock);
if (mListener.onImageAvailable == nullptr) {
return; // No callback registered
}
@@ -143,12 +143,12 @@
void
AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
- Mutex::Autolock _l(mLock);
sp<AImageReader> reader = mReader.promote();
if (reader == nullptr) {
ALOGW("A frame is available after AImageReader closed!");
return; // reader has been closed
}
+ Mutex::Autolock _l(mLock);
if (mListener.onBufferRemoved == nullptr) {
return; // No callback registered
}
@@ -272,6 +272,11 @@
mFrameListener(new FrameListener(this)),
mBufferRemovedListener(new BufferRemovedListener(this)) {}
+AImageReader::~AImageReader() {
+ Mutex::Autolock _l(mLock);
+ LOG_FATAL_IF("AImageReader not closed before destruction", mIsClosed != true);
+}
+
media_status_t
AImageReader::init() {
PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
@@ -347,8 +352,12 @@
return AMEDIA_OK;
}
-AImageReader::~AImageReader() {
+void AImageReader::close() {
Mutex::Autolock _l(mLock);
+ if (mIsClosed) {
+ return;
+ }
+ mIsClosed = true;
AImageReader_ImageListener nullListener = {nullptr, nullptr};
setImageListenerLocked(&nullListener);
@@ -741,6 +750,7 @@
void AImageReader_delete(AImageReader* reader) {
ALOGV("%s", __FUNCTION__);
if (reader != nullptr) {
+ reader->close();
reader->decStrong((void*) AImageReader_delete);
}
return;
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index e328cb1..0779a71 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -76,6 +76,7 @@
int32_t getHeight() const { return mHeight; };
int32_t getFormat() const { return mFormat; };
int32_t getMaxImages() const { return mMaxImages; };
+ void close();
private:
@@ -134,7 +135,7 @@
private:
AImageReader_ImageListener mListener = {nullptr, nullptr};
- wp<AImageReader> mReader;
+ const wp<AImageReader> mReader;
Mutex mLock;
};
sp<FrameListener> mFrameListener;
@@ -149,7 +150,7 @@
private:
AImageReader_BufferRemovedListener mListener = {nullptr, nullptr};
- wp<AImageReader> mReader;
+ const wp<AImageReader> mReader;
Mutex mLock;
};
sp<BufferRemovedListener> mBufferRemovedListener;
@@ -165,6 +166,7 @@
native_handle_t* mWindowHandle = nullptr;
List<AImage*> mAcquiredImages;
+ bool mIsClosed = false;
Mutex mLock;
};
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 51b516a..af21a99 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -221,7 +221,13 @@
break;
}
- AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(&format);
+ // Here format is MediaCodec's internal copy of output format.
+ // Make a copy since the client might modify it.
+ sp<AMessage> copy;
+ if (format != nullptr) {
+ copy = format->dup();
+ }
+ AMediaFormat *aMediaFormat = AMediaFormat_fromMsg(©);
Mutex::Autolock _l(mCodec->mAsyncCallbackLock);
if (mCodec->mAsyncCallbackUserData != NULL
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index e567613..f6892e6 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -26,16 +26,16 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_util_Binder.h>
#include <cutils/properties.h>
-#include <utils/Log.h>
-#include <utils/StrongPointer.h>
+#include <datasource/DataSourceFactory.h>
+#include <datasource/HTTPBase.h>
+#include <datasource/NuCachedSource2.h>
#include <media/IMediaHTTPService.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaDataSource.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
-#include "../../libstagefright/include/HTTPBase.h"
-#include "../../libstagefright/include/NuCachedSource2.h"
#include "NdkMediaDataSourceCallbacksPriv.h"
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 60f3e8e..842216c 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -89,7 +89,7 @@
};
void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
- if (!mEventListener && !mExpirationUpdateListener && !mKeysChangeListener) {
+ if (!mEventListener || !mExpirationUpdateListener || !mKeysChangeListener) {
ALOGE("No listeners are specified");
return;
}
diff --git a/media/tests/benchmark/Android.bp b/media/tests/benchmark/Android.bp
index 8a7a59f..de408dd 100644
--- a/media/tests/benchmark/Android.bp
+++ b/media/tests/benchmark/Android.bp
@@ -17,4 +17,5 @@
subdirs = [
"src",
"tests",
-]
\ No newline at end of file
+ "MediaBenchmarkTest",
+]
diff --git a/media/tests/benchmark/MediaBenchmarkTest/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
new file mode 100644
index 0000000..91b03f1
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+android_test {
+ name: "MediaBenchmarkTest",
+
+ // Include all the test code
+ srcs: ["src/androidTest/**/*.java"],
+
+ sdk_version: "system_current",
+
+ resource_dirs: ["res"],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+
+ static_libs: [
+ "libMediaBenchmark",
+ "junit",
+ "androidx.test.runner",
+ ],
+}
+
+android_library {
+ name: "libMediaBenchmark",
+
+ // Include all the libraries
+ srcs: ["src/main/**/*.java"],
+
+ sdk_version: "system_current",
+
+ static_libs: [
+ "androidx.test.core",
+ ],
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
new file mode 100644
index 0000000..eea9914
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ package="com.android.media.benchmark">
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
+
+ <application
+ tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon"
+ tools:remove="android:appComponentFactory">
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.media.benchmark"
+ android:label="Benchmark Media Test"/>
+</manifest>
\ No newline at end of file
diff --git a/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml b/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml
new file mode 100644
index 0000000..89d6ce2
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Media Benchmark Tests">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="MediaBenchmarkTest.apk" />
+ </target_preparer>
+
+ <option name="test-tag" value="MediaBenchmarkTest" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.media.benchmark" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/build.gradle b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
new file mode 100644
index 0000000..b0ee692
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.5.0'
+ }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 29
+ defaultConfig {
+ applicationId "com.android.media.benchmark"
+ minSdkVersion 21
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ sourceSets {
+ main {
+ java.srcDirs 'src/main/java'
+ res.srcDirs 'res'
+ manifest.srcFile 'AndroidManifest.xml'
+ }
+ androidTest {
+ java.srcDirs 'src/androidTest/java'
+ res.srcDirs 'res'
+ manifest.srcFile 'AndroidManifest.xml'
+ }
+ }
+}
+
+repositories {
+ google()
+ jcenter()
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.1'
+}
\ No newline at end of file
diff --git a/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
new file mode 100644
index 0000000..24dbccc
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/res/values/strings.xml
@@ -0,0 +1,4 @@
+<resources>
+ <string name="input_file_path">/data/local/tmp/MediaBenchmark/res/</string>
+ <string name="output_file_path">/data/local/tmp/MediaBenchmark/output/</string>
+</resources>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
new file mode 100644
index 0000000..be2633d
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
@@ -0,0 +1,197 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.tests;
+
+import android.content.Context;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.CodecUtils;
+import com.android.media.benchmark.library.Decoder;
+import com.android.media.benchmark.library.Extractor;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+
+@RunWith(Parameterized.class)
+public class DecoderTest {
+ private static final Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String mOutputFilePath = mContext.getString(R.string.output_file_path);
+ private static final String TAG = "DecoderTest";
+ private static final long PER_TEST_TIMEOUT_MS = 60000;
+ private static final boolean DEBUG = false;
+ private static final boolean WRITE_OUTPUT = false;
+ private String mInputFile;
+ private boolean mAsyncMode;
+
+ public DecoderTest(String inputFile, boolean asyncMode) {
+ this.mInputFile = inputFile;
+ this.mAsyncMode = asyncMode;
+ }
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> input() {
+ return Arrays.asList(new Object[][]{
+ //Audio Sync Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", false},
+ {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", false},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", false},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", false},
+ {"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", false},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", false},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", false},
+ // Audio Async Test
+ {"bbb_44100hz_2ch_128kbps_aac_30sec.mp4", true},
+ {"bbb_44100hz_2ch_128kbps_mp3_30sec.mp3", true},
+ {"bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", true},
+ {"bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", true},
+ {"bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", true},
+ {"bbb_44100hz_2ch_600kbps_flac_30sec.mp4", true},
+ {"bbb_48000hz_2ch_100kbps_opus_30sec.webm", true},
+ // Video Sync Test
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", false},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", false},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", false},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", false},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", false},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", false},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", false},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", false},
+ // Video Async Test
+ {"crowd_1920x1080_25fps_4000kbps_vp9.webm", true},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", true},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", true},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", true},
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", true},
+ {"crowd_352x288_25fps_6000kbps_h263.3gp", true},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", true},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", true}});
+ }
+
+ @Test(timeout = PER_TEST_TIMEOUT_MS)
+ public void testDecoder() throws IOException {
+ File inputFile = new File(mInputFilePath + mInputFile);
+ if (inputFile.exists()) {
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ int trackCount = extractor.setUpExtractor(fileDescriptor);
+ ArrayList<ByteBuffer> inputBuffer = new ArrayList<>();
+ ArrayList<MediaCodec.BufferInfo> frameInfo = new ArrayList<>();
+ if (trackCount <= 0) {
+ Log.e(TAG, "Extraction failed. No tracks for file: " + mInputFile);
+ return;
+ }
+ for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) {
+ extractor.selectExtractorTrack(currentTrack);
+ MediaFormat format = extractor.getFormat(currentTrack);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+ if (mediaCodecs.size() <= 0) {
+ Log.e(TAG,
+ "No suitable codecs found for file: " + mInputFile
+ + " track : " + currentTrack + " mime: " + mime);
+ continue;
+ }
+ // Get samples from extractor
+ int sampleSize;
+ do {
+ sampleSize = extractor.getFrameSample();
+ MediaCodec.BufferInfo bufInfo = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo info = extractor.getBufferInfo();
+ ByteBuffer dataBuffer = ByteBuffer.allocate(info.size);
+ dataBuffer.put(extractor.getFrameBuffer().array(), 0, info.size);
+ bufInfo.set(info.offset, info.size, info.presentationTimeUs, info.flags);
+ inputBuffer.add(dataBuffer);
+ frameInfo.add(bufInfo);
+ if (DEBUG) {
+ Log.d(TAG,
+ "Extracted bufInfo: flag = " + bufInfo.flags + " timestamp = "
+ + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ } while (sampleSize > 0);
+ for (String codecName : mediaCodecs) {
+ FileOutputStream decodeOutputStream = null;
+ if (WRITE_OUTPUT) {
+ if (!Paths.get(mOutputFilePath).toFile().exists()) {
+ Files.createDirectories(Paths.get(mOutputFilePath));
+ }
+ File outFile = new File(mOutputFilePath + "decoder.out");
+ if (outFile.exists()) {
+ if (!outFile.delete()) {
+ Log.e(TAG, " Unable to delete existing file" + outFile.toString());
+ }
+ }
+ if (outFile.createNewFile()) {
+ decodeOutputStream = new FileOutputStream(outFile);
+ } else {
+ Log.e(TAG, "Unable to create file: " + outFile.toString());
+ }
+ }
+ Decoder decoder = new Decoder();
+ decoder.setupDecoder(decodeOutputStream);
+ int status =
+ decoder.decode(inputBuffer, frameInfo, mAsyncMode, format, codecName);
+ decoder.deInitCodec();
+ if (status == 0) {
+ decoder.dumpStatistics(
+ mInputFile + " " + codecName, extractor.getClipDuration());
+ Log.i(TAG,
+ "Decoding Successful for file: " + mInputFile
+ + " with codec: " + codecName);
+ } else {
+ Log.e(TAG,
+ "Decoder returned error " + status + " for file: " + mInputFile
+ + " with codec: " + codecName);
+ }
+ decoder.resetDecoder();
+ if (decodeOutputStream != null) {
+ decodeOutputStream.close();
+ }
+ }
+ extractor.unselectExtractorTrack(currentTrack);
+ inputBuffer.clear();
+ frameInfo.clear();
+ }
+ extractor.deinitExtractor();
+ fileInput.close();
+ } else {
+ Log.w(TAG,
+ "Warning: Test Skipped. Cannot find " + mInputFile + " in directory "
+ + mInputFilePath);
+ }
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java
new file mode 100644
index 0000000..a02011c
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/ExtractorTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.tests;
+
+import com.android.media.benchmark.R;
+import com.android.media.benchmark.library.Extractor;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+@RunWith(Parameterized.class)
+public class ExtractorTest {
+ private static Context mContext =
+ InstrumentationRegistry.getInstrumentation().getTargetContext();
+ private static final String mInputFilePath = mContext.getString(R.string.input_file_path);
+ private static final String TAG = "ExtractorTest";
+ private String mInputFileName;
+ private int mTrackId;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> inputFiles() {
+ return Arrays.asList(new Object[][]{/* Parameters: filename, trackId*/
+ {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", 0},
+ {"crowd_1920x1080_25fps_6700kbps_h264.ts", 0},
+ {"crowd_1920x1080_25fps_7300kbps_mpeg2.mp4", 0},
+ {"crowd_1920x1080_25fps_4000kbps_av1.webm", 0},
+ {"crowd_1920x1080_25fps_4000kbps_h265.mkv", 0},
+ {"crowd_1920x1080_25fps_4000kbps_vp8.webm", 0},
+ {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", 0},
+ {"bbb_44100hz_2ch_128kbps_mp3_5mins.mp3", 0},
+ {"bbb_44100hz_2ch_600kbps_flac_5mins.flac", 0},
+ {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", 0},
+ {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", 0},
+ {"bbb_44100hz_2ch_80kbps_vorbis_5mins.mp4", 0},
+ {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", 0}});
+ }
+
+ public ExtractorTest(String filename, int track) {
+ this.mInputFileName = filename;
+ this.mTrackId = track;
+ }
+
+ @Test
+ public void sampleExtractTest() throws IOException {
+ int status = -1;
+ File inputFile = new File(mInputFilePath + mInputFileName);
+ if (inputFile.exists()) {
+ FileInputStream fileInput = new FileInputStream(inputFile);
+ FileDescriptor fileDescriptor = fileInput.getFD();
+ Extractor extractor = new Extractor();
+ extractor.setUpExtractor(fileDescriptor);
+ status = extractor.extractSample(mTrackId);
+ extractor.deinitExtractor();
+ extractor.dumpStatistics(mInputFileName);
+ fileInput.close();
+ } else {
+ Log.e(TAG, "Cannot find " + mInputFileName + " in directory " + mInputFilePath);
+ }
+ assertThat(status, is(equalTo(0)));
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
new file mode 100644
index 0000000..08035c9
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
@@ -0,0 +1,39 @@
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.os.Build;
+
+import java.util.ArrayList;
+
+public class CodecUtils {
+ private CodecUtils() {}
+
+ /**
+ * Queries the MediaCodecList and returns codec names of supported codecs.
+ *
+ * @param mimeType Mime type of input
+ * @param isEncoder Specifies encoder or decoder
+ * @return ArrayList of codec names
+ */
+ public static ArrayList<String> selectCodecs(String mimeType, boolean isEncoder) {
+ MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
+ ArrayList<String> supportedCodecs = new ArrayList<>();
+ for (MediaCodecInfo codecInfo : codecInfos) {
+ if (isEncoder != codecInfo.isEncoder()) {
+ continue;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && codecInfo.isAlias()) {
+ continue;
+ }
+ String[] types = codecInfo.getSupportedTypes();
+ for (String type : types) {
+ if (type.equalsIgnoreCase(mimeType)) {
+ supportedCodecs.add(codecInfo.getName());
+ }
+ }
+ }
+ return supportedCodecs;
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
new file mode 100644
index 0000000..2cd27c2
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+public class Decoder {
+ private static final String TAG = "Decoder";
+ private static final boolean DEBUG = false;
+ private static final int kQueueDequeueTimeoutUs = 1000;
+
+ private final Object mLock = new Object();
+ private MediaCodec mCodec;
+ private ArrayList<BufferInfo> mInputBufferInfo;
+ private Stats mStats;
+
+ private boolean mSawInputEOS;
+ private boolean mSawOutputEOS;
+ private boolean mSignalledError;
+
+ private int mNumOutputFrame;
+ private int mIndex;
+
+ private ArrayList<ByteBuffer> mInputBuffer;
+ private FileOutputStream mOutputStream;
+
+ public Decoder() { mStats = new Stats(); }
+
+ /**
+ * Setup of decoder
+ *
+ * @param outputStream Will dump the output in this stream if not null.
+ */
+ public void setupDecoder(FileOutputStream outputStream) {
+ mSignalledError = false;
+ mOutputStream = outputStream;
+ }
+
+ private MediaCodec createCodec(String codecName, MediaFormat format) throws IOException {
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ try {
+ MediaCodec codec;
+ if (codecName.isEmpty()) {
+ Log.i(TAG, "File mime type: " + mime);
+ if (mime != null) {
+ codec = MediaCodec.createDecoderByType(mime);
+ Log.i(TAG, "Decoder created for mime type " + mime);
+ return codec;
+ } else {
+ Log.e(TAG, "Mime type is null, please specify a mime type to create decoder");
+ return null;
+ }
+ } else {
+ codec = MediaCodec.createByCodecName(codecName);
+ Log.i(TAG, "Decoder created with codec name: " + codecName + " mime: " + mime);
+ return codec;
+ }
+ } catch (IllegalArgumentException ex) {
+ ex.printStackTrace();
+ Log.e(TAG, "Failed to create decoder for " + codecName + " mime:" + mime);
+ return null;
+ }
+ }
+
+ /**
+ * Decodes the given input buffer,
+ * provided valid list of buffer info and format are passed as inputs.
+ *
+ * @param inputBuffer Decode the provided list of ByteBuffers
+ * @param inputBufferInfo List of buffer info corresponding to provided input buffers
+ * @param asyncMode Will run on async implementation if true
+ * @param format For creating the decoder if codec name is empty and configuring it
+ * @param codecName Will create the decoder with codecName
+ * @return 0 if decode was successful , -1 for fail, -2 for decoder not created
+ * @throws IOException if the codec cannot be created.
+ */
+ public int decode(@NonNull ArrayList<ByteBuffer> inputBuffer,
+ @NonNull ArrayList<BufferInfo> inputBufferInfo, final boolean asyncMode,
+ @NonNull MediaFormat format, String codecName) throws IOException {
+ mInputBuffer = new ArrayList<>(inputBuffer.size());
+ mInputBuffer.addAll(inputBuffer);
+ mInputBufferInfo = new ArrayList<>(inputBufferInfo.size());
+ mInputBufferInfo.addAll(inputBufferInfo);
+ mSawInputEOS = false;
+ mSawOutputEOS = false;
+ mNumOutputFrame = 0;
+ mIndex = 0;
+ long sTime = mStats.getCurTime();
+ mCodec = createCodec(codecName, format);
+ if (mCodec == null) {
+ return -2;
+ }
+ if (asyncMode) {
+ mCodec.setCallback(new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(
+ @NonNull MediaCodec mediaCodec, int inputBufferId) {
+ try {
+ mStats.addInputTime();
+ onInputAvailable(inputBufferId, mediaCodec);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
+ mStats.addOutputTime();
+ onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Saw output EOS");
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onOutputFormatChanged(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
+ Log.i(TAG, "Output format changed. Format: " + format.toString());
+ }
+
+ @Override
+ public void onError(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+ mSignalledError = true;
+ Log.e(TAG, "Codec Error: " + e.toString());
+ e.printStackTrace();
+ synchronized (mLock) { mLock.notify(); }
+ }
+ });
+ }
+ int isEncoder = 0;
+ if (DEBUG) {
+ Log.d(TAG, "Media Format : " + format.toString());
+ }
+ mCodec.configure(format, null, null, isEncoder);
+ mCodec.start();
+ Log.i(TAG, "Codec started ");
+ long eTime = mStats.getCurTime();
+ mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
+ mStats.setStartTime();
+ if (asyncMode) {
+ try {
+ synchronized (mLock) { mLock.wait(); }
+ if (mSignalledError) {
+ return -1;
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ } else {
+ while (!mSawOutputEOS && !mSignalledError) {
+ /* Queue input data */
+ if (!mSawInputEOS) {
+ int inputBufferId = mCodec.dequeueInputBuffer(kQueueDequeueTimeoutUs);
+ if (inputBufferId < 0 && inputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG,
+ "MediaCodec.dequeueInputBuffer "
+ + " returned invalid index : " + inputBufferId);
+ return -1;
+ }
+ mStats.addInputTime();
+ onInputAvailable(inputBufferId, mCodec);
+ }
+ /* Dequeue output data */
+ BufferInfo outputBufferInfo = new BufferInfo();
+ int outputBufferId =
+ mCodec.dequeueOutputBuffer(outputBufferInfo, kQueueDequeueTimeoutUs);
+ if (outputBufferId < 0) {
+ if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
+ MediaFormat outFormat = mCodec.getOutputFormat();
+ Log.i(TAG, "Output format changed. Format: " + outFormat.toString());
+ } else if (outputBufferId == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
+ Log.i(TAG, "Ignoring deprecated flag: INFO_OUTPUT_BUFFERS_CHANGED");
+ } else if (outputBufferId != MediaCodec.INFO_TRY_AGAIN_LATER) {
+ Log.e(TAG,
+ "MediaCodec.dequeueOutputBuffer"
+ + " returned invalid index " + outputBufferId);
+ return -1;
+ }
+ } else {
+ mStats.addOutputTime();
+ if (DEBUG) {
+ Log.d(TAG, "Dequeue O/P buffer with BufferID " + outputBufferId);
+ }
+ onOutputAvailable(mCodec, outputBufferId, outputBufferInfo);
+ }
+ if (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+ Log.i(TAG, "Saw output EOS");
+ }
+ }
+ }
+ mInputBuffer.clear();
+ mInputBufferInfo.clear();
+ return 0;
+ }
+
+ /**
+ * Stops the codec and releases codec resources.
+ */
+ public void deInitCodec() {
+ long sTime = mStats.getCurTime();
+ if (mCodec != null) {
+ mCodec.stop();
+ mCodec.release();
+ mCodec = null;
+ }
+ long eTime = mStats.getCurTime();
+ mStats.setDeInitTime(mStats.getTimeDiff(sTime, eTime));
+ }
+
+ /**
+ * Prints out the statistics in the information log
+ *
+ * @param inputReference The operation being performed, in this case decode
+ * @param durationUs Duration of the clip in microseconds
+ */
+ public void dumpStatistics(String inputReference, long durationUs) {
+ String operation = "decode";
+ mStats.dumpStatistics(operation, inputReference, durationUs);
+ }
+
+ /**
+ * Resets the stats
+ */
+ public void resetDecoder() { mStats.reset(); }
+
+ private void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
+ if ((inputBufferId >= 0) && !mSawInputEOS) {
+ ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
+ BufferInfo bufInfo = mInputBufferInfo.get(mIndex);
+ inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
+ mIndex++;
+ if (bufInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
+ mSawInputEOS = true;
+ Log.i(TAG, "Saw input EOS");
+ }
+ mStats.addFrameSize(bufInfo.size);
+ mediaCodec.queueInputBuffer(inputBufferId, bufInfo.offset, bufInfo.size,
+ bufInfo.presentationTimeUs, bufInfo.flags);
+ if (DEBUG) {
+ Log.d(TAG,
+ "Codec Input: "
+ + "flag = " + bufInfo.flags + " timestamp = "
+ + bufInfo.presentationTimeUs + " size = " + bufInfo.size);
+ }
+ }
+ }
+
+ private void onOutputAvailable(
+ MediaCodec mediaCodec, int outputBufferId, BufferInfo outputBufferInfo) {
+ if (mSawOutputEOS || outputBufferId < 0) {
+ return;
+ }
+ mNumOutputFrame++;
+ if (DEBUG) {
+ Log.d(TAG,
+ "In OutputBufferAvailable ,"
+ + " output frame number = " + mNumOutputFrame);
+ }
+ if (mOutputStream != null) {
+ try {
+ ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferId);
+ byte[] bytesOutput = new byte[outputBuffer.remaining()];
+ outputBuffer.get(bytesOutput);
+ mOutputStream.write(bytesOutput);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+ }
+ }
+ mediaCodec.releaseOutputBuffer(outputBufferId, false);
+ mSawOutputEOS = (outputBufferInfo.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
new file mode 100644
index 0000000..459e2a9
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.media.MediaCodec;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+public class Extractor {
+ private static final String TAG = "Extractor";
+ private static final int kMaxBufSize = 1024 * 1024 * 16;
+ private MediaExtractor mExtractor;
+ private ByteBuffer mFrameBuffer;
+ private MediaCodec.BufferInfo mBufferInfo;
+ private Stats mStats;
+ private long mDurationUs;
+
+ public Extractor() {
+ mFrameBuffer = ByteBuffer.allocate(kMaxBufSize);
+ mBufferInfo = new MediaCodec.BufferInfo();
+ mStats = new Stats();
+ }
+
+ /**
+ * Creates a Media Extractor and sets data source(FileDescriptor)to use
+ *
+ * @param fileDescriptor FileDescriptor for the file which is to be extracted
+ * @return TrackCount of the sample
+ * @throws IOException If FileDescriptor is null
+ */
+ public int setUpExtractor(FileDescriptor fileDescriptor) throws IOException {
+ long sTime = mStats.getCurTime();
+ mExtractor = new MediaExtractor();
+ mExtractor.setDataSource(fileDescriptor);
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setInitTime(timeTaken);
+ return mExtractor.getTrackCount();
+ }
+
+ /**
+ * Returns the track format of the specified index
+ *
+ * @param trackID Index of the track
+ * @return Format of the track
+ */
+ public MediaFormat getFormat(int trackID) { return mExtractor.getTrackFormat(trackID); }
+
+ /**
+ * Returns the extracted buffer for the input clip
+ */
+ public ByteBuffer getFrameBuffer() { return this.mFrameBuffer; }
+
+ /**
+ * Returns the information of buffer related to sample
+ */
+ public MediaCodec.BufferInfo getBufferInfo() { return this.mBufferInfo; }
+
+ /**
+ * Returns the duration of the sample
+ */
+ public long getClipDuration() { return this.mDurationUs; }
+
+ /**
+ * Retrieve the current sample and store it in the byte buffer
+ * Also, sets the information related to extracted sample and store it in buffer info
+ *
+ * @return Sample size of the extracted sample
+ */
+ public int getFrameSample() {
+ int sampleSize = mExtractor.readSampleData(mFrameBuffer, 0);
+ if (sampleSize < 0) {
+ mBufferInfo.flags = MediaCodec.BUFFER_FLAG_END_OF_STREAM;
+ mBufferInfo.size = 0;
+ } else {
+ mBufferInfo.size = sampleSize;
+ mBufferInfo.offset = 0;
+ mBufferInfo.flags = mExtractor.getSampleFlags();
+ mBufferInfo.presentationTimeUs = mExtractor.getSampleTime();
+ mExtractor.advance();
+ }
+ return sampleSize;
+ }
+
+ /**
+ * Setup the track format and get the duration of the sample
+ * Track is selected here for extraction
+ *
+ * @param trackId Track index to be selected
+ * @return 0 for valid track, otherwise -1
+ */
+ public int selectExtractorTrack(int trackId) {
+ MediaFormat trackFormat = mExtractor.getTrackFormat(trackId);
+ mDurationUs = trackFormat.getLong(MediaFormat.KEY_DURATION);
+ if (mDurationUs < 0) {
+ Log.e(TAG, "Invalid Clip");
+ return -1;
+ }
+ mExtractor.selectTrack(trackId);
+ return 0;
+ }
+
+ /**
+ * Unselect the track
+ *
+ * @param trackId Track Index to be unselected
+ */
+ public void unselectExtractorTrack(int trackId) { mExtractor.unselectTrack(trackId); }
+
+ /**
+ * Free up the resources
+ */
+ public void deinitExtractor() {
+ long sTime = mStats.getCurTime();
+ mExtractor.release();
+ long eTime = mStats.getCurTime();
+ long timeTaken = mStats.getTimeDiff(sTime, eTime);
+ mStats.setDeInitTime(timeTaken);
+ }
+
+ /**
+ * Performs extract operation
+ *
+ * @param currentTrack Track index to be extracted
+ * @return Status as 0 if extraction is successful, -1 otherwise
+ */
+ public int extractSample(int currentTrack) {
+ int status;
+ status = selectExtractorTrack(currentTrack);
+ if (status == -1) {
+ Log.e(TAG, "Failed to select track");
+ return -1;
+ }
+ mStats.setStartTime();
+ while (true) {
+ int readSampleSize = getFrameSample();
+ if (readSampleSize <= 0) {
+ break;
+ }
+ mStats.addOutputTime();
+ mStats.addFrameSize(readSampleSize);
+ }
+ unselectExtractorTrack(currentTrack);
+ return 0;
+ }
+
+ /**
+ * Write the benchmark logs for the given input file
+ *
+ * @param inputReference Name of the input file
+ */
+ public void dumpStatistics(String inputReference) {
+ String operation = "extract";
+ mStats.dumpStatistics(operation, inputReference, mDurationUs);
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
new file mode 100644
index 0000000..18ab5be
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Measures Performance.
+ */
+public class Stats {
+ private static final String TAG = "Stats";
+ private long mInitTimeNs;
+ private long mDeInitTimeNs;
+ private long mStartTimeNs;
+ private ArrayList<Integer> mFrameSizes;
+ private ArrayList<Long> mInputTimer;
+ private ArrayList<Long> mOutputTimer;
+
+ public Stats() {
+ mFrameSizes = new ArrayList<>();
+ mInputTimer = new ArrayList<>();
+ mOutputTimer = new ArrayList<>();
+ mInitTimeNs = 0;
+ mDeInitTimeNs = 0;
+ }
+
+ public long getCurTime() { return System.nanoTime(); }
+
+ public void setInitTime(long initTime) { mInitTimeNs = initTime; }
+
+ public void setDeInitTime(long deInitTime) { mDeInitTimeNs = deInitTime; }
+
+ public void setStartTime() { mStartTimeNs = System.nanoTime(); }
+
+ public void addFrameSize(int size) { mFrameSizes.add(size); }
+
+ public void addInputTime() { mInputTimer.add(System.nanoTime()); }
+
+ public void addOutputTime() { mOutputTimer.add(System.nanoTime()); }
+
+ public void reset() {
+ if (mFrameSizes.size() != 0) {
+ mFrameSizes.clear();
+ }
+
+ if (mInputTimer.size() != 0) {
+ mInputTimer.clear();
+ }
+
+ if (mOutputTimer.size() != 0) {
+ mOutputTimer.clear();
+ }
+ }
+
+ public long getInitTime() { return mInitTimeNs; }
+
+ public long getDeInitTime() { return mDeInitTimeNs; }
+
+ public long getTimeDiff(long sTime, long eTime) { return (eTime - sTime); }
+
+ private long getTotalTime() {
+ if (mOutputTimer.size() == 0) {
+ return -1;
+ }
+ long lastTime = mOutputTimer.get(mOutputTimer.size() - 1);
+ return lastTime - mStartTimeNs;
+ }
+
+ private long getTotalSize() {
+ long totalSize = 0;
+ for (long size : mFrameSizes) {
+ totalSize += size;
+ }
+ return totalSize;
+ }
+
+ /**
+ * Dumps the stats of the operation for a given input media.
+ * <p>
+ * \param operation describes the operation performed on the input media
+ * (i.e. extract/mux/decode/encode)
+ * \param inputReference input media
+ * \param durationUs is a duration of the input media in microseconds.
+ */
+ public void dumpStatistics(String operation, String inputReference, long durationUs) {
+ if (mOutputTimer.size() == 0) {
+ Log.e(TAG, "No output produced");
+ return;
+ }
+ long totalTimeTakenNs = getTotalTime();
+ long timeTakenPerSec = (totalTimeTakenNs * 1000000) / durationUs;
+ long timeToFirstFrameNs = mOutputTimer.get(0) - mStartTimeNs;
+ long size = getTotalSize();
+ // get min and max output intervals.
+ long intervalNs;
+ long minTimeTakenNs = Long.MAX_VALUE;
+ long maxTimeTakenNs = 0;
+ long prevIntervalNs = mStartTimeNs;
+ for (int idx = 0; idx < mOutputTimer.size() - 1; idx++) {
+ intervalNs = mOutputTimer.get(idx) - prevIntervalNs;
+ prevIntervalNs = mOutputTimer.get(idx);
+ if (minTimeTakenNs > intervalNs) {
+ minTimeTakenNs = intervalNs;
+ } else if (maxTimeTakenNs < intervalNs) {
+ maxTimeTakenNs = intervalNs;
+ }
+ }
+ // Print the Stats
+ Log.i(TAG, "Input Reference : " + inputReference);
+ Log.i(TAG, "Setup Time in nano sec : " + mInitTimeNs);
+ Log.i(TAG, "Average Time in nano sec : " + totalTimeTakenNs / mOutputTimer.size());
+ Log.i(TAG, "Time to first frame in nano sec : " + timeToFirstFrameNs);
+ Log.i(TAG, "Time taken (in nano sec) to " + operation + " 1 sec of content : " +
+ timeTakenPerSec);
+ Log.i(TAG, "Total bytes " + operation + "ed : " + size);
+ Log.i(TAG, "Number of bytes " + operation + "ed per second : " +
+ (size * 1000000000) / totalTimeTakenNs);
+ Log.i(TAG, "Minimum Time in nano sec : " + minTimeTakenNs);
+ Log.i(TAG, "Maximum Time in nano sec : " + maxTimeTakenNs);
+ Log.i(TAG, "Destroy Time in nano sec : " + mDeInitTimeNs);
+ }
+}
\ No newline at end of file
diff --git a/media/tests/benchmark/README.md b/media/tests/benchmark/README.md
index 8db3fd3..d1354b3 100644
--- a/media/tests/benchmark/README.md
+++ b/media/tests/benchmark/README.md
@@ -1,9 +1,16 @@
# Benchmark tests
+Benchmark app analyses the time taken by MediaCodec, MediaExtractor and MediaMuxer for given set of inputs. It is used to benchmark these modules on android devices.
+Benchmark results are emitted to logcat.
+
+This page describes steps to run the NDK and SDK layer test.
+
Run the following steps to build the test suite:
```
mmm frameworks/av/media/tests/benchmark/
```
+To run the test suite for measuring performance of the native layer, follow the following steps:
+# NDK
The binaries will be created in the following path : ${OUT}/data/nativetest64/
@@ -13,20 +20,25 @@
To run the binary, follow the commands mentioned below under each module.
-The resource files for the tests are taken from [here](https://drive.google.com/open?id=1ghMr17BBJ7n0pqbm7oREiTN_MNemJUqy)
+The resource file for the tests is taken from [here](https://drive.google.com/open?id=1ghMr17BBJ7n0pqbm7oREiTN_MNemJUqy)
+
+Download the MediaBenchmark.zip file, unzip and push it to /data/local/tmp/ on the device.
+
+```
+unzip MediaBenchmark.zip
+adb push MediaBenchmark /data/local/tmp
+```
## Extractor
The test extracts elementary stream and benchmarks the extractors available in NDK.
-Push the resource files to /sdcard/res on the device.
-
-You can use a different location, but you have to modify the rest of the instructions to replace /sdcard/res with wherever you chose to put the files.
+The resource files are assumed to be at /data/local/tmp/MediaBenchmark/res/. You can use a different location, but you have to modify the rest of the instructions to replace /data/local/tmp/MediaBenchmark/res/ with wherever you chose to put the files.
The path to these files on the device is required to be given for the test.
```
-adb shell /data/local/tmp/extractorTest -P /sdcard/res/
+adb shell /data/local/tmp/extractorTest -P /data/local/tmp/MediaBenchmark/res/
```
## Decoder
@@ -36,7 +48,7 @@
Setup steps are same as extractor.
```
-adb shell /data/local/tmp/decoderTest -P /sdcard/res/
+adb shell /data/local/tmp/decoderTest -P /data/local/tmp/MediaBenchmark/res/
```
## Muxer
@@ -46,7 +58,7 @@
Setup steps are same as extractor.
```
-adb shell /data/local/tmp/muxerTest -P /sdcard/res/
+adb shell /data/local/tmp/muxerTest -P /data/local/tmp/MediaBenchmark/res/
```
## Encoder
@@ -56,5 +68,38 @@
Setup steps are same as extractor.
```
-adb shell /data/local/tmp/encoderTest -P /sdcard/res/
+adb shell /data/local/tmp/encoderTest -P /data/local/tmp/MediaBenchmark/res/
+```
+
+# SDK
+
+To run the test suite for measuring performance of the SDK APIs, follow the following steps:
+
+The apk will be created at the following path:
+${OUT}/testcases/MediaBenchmarkApp/arm64/
+
+To get the resorce files for the test follow instructions given in [NDK](#NDK)
+
+For installing the apk, run the command:
+```
+adb install -f -r ${OUT}/testcases/MediaBenchmarkApp/arm64/MediaBenchmarkApp.apk
+```
+
+For running all the tests, run the command:
+```
+adb shell am instrument -w -r -e package com.android.media.benchmark.tests com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Extractor
+
+The test extracts elementary stream and benchmarks the extractors available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.ExtractorTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
+```
+
+## Decoder
+
+The test decodes input stream and benchmarks the decoders available in SDK.
+```
+adb shell am instrument -w -r -e class 'com.android.media.benchmark.tests.DecoderTest' com.android.media.benchmark/androidx.test.runner.AndroidJUnitRunner
```
diff --git a/media/tests/benchmark/tests/DecoderTest.cpp b/media/tests/benchmark/tests/DecoderTest.cpp
index 6cb42d6..242178f 100644
--- a/media/tests/benchmark/tests/DecoderTest.cpp
+++ b/media/tests/benchmark/tests/DecoderTest.cpp
@@ -72,24 +72,7 @@
vector<AMediaCodecBufferInfo> frameInfo;
AMediaCodecBufferInfo info;
uint32_t inputBufferOffset = 0;
- int32_t idx = 0;
- // Get CSD data
- while (1) {
- void *csdBuffer = extractor->getCSDSample(info, idx);
- if (!csdBuffer || !info.size) break;
-
- // copy the meta data and buffer to be passed to decoder
- if (inputBufferOffset + info.size > kMaxBufferSize) {
- cout << "[ WARN ] Test Skipped. Memory allocated not sufficient\n";
- free(inputBuffer);
- return;
- }
- memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
- frameInfo.push_back(info);
- inputBufferOffset += info.size;
- idx++;
- }
// Get frame data
while (1) {
status = extractor->getFrameSample(info);
@@ -135,6 +118,7 @@
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", false),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
INSTANTIATE_TEST_SUITE_P(
@@ -144,6 +128,7 @@
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
make_tuple("bbb_44100hz_2ch_80kbps_vorbis_30sec.mp4", "", true),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
INSTANTIATE_TEST_SUITE_P(VideDecoderSyncTest, DecoderTest,
diff --git a/media/tests/benchmark/tests/EncoderTest.cpp b/media/tests/benchmark/tests/EncoderTest.cpp
index 574083d..9f42c64 100644
--- a/media/tests/benchmark/tests/EncoderTest.cpp
+++ b/media/tests/benchmark/tests/EncoderTest.cpp
@@ -72,24 +72,6 @@
vector<AMediaCodecBufferInfo> frameInfo;
AMediaCodecBufferInfo info;
uint32_t inputBufferOffset = 0;
- int32_t idx = 0;
-
- // Get CSD data
- while (1) {
- void *csdBuffer = extractor->getCSDSample(info, idx);
- if (!csdBuffer || !info.size) break;
-
- // copy the meta data and buffer to be passed to decoder
- if (inputBufferOffset + info.size > kMaxBufferSize) {
- cout << "[ WARN ] Test Skipped. Memory allocated not sufficient\n";
- free(inputBuffer);
- return;
- }
- memcpy(inputBuffer + inputBufferOffset, csdBuffer, info.size);
- frameInfo.push_back(info);
- inputBufferOffset += info.size;
- idx++;
- }
// Get frame data
while (1) {
@@ -189,6 +171,7 @@
::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", false),
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", false),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", false),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", false),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", false)));
INSTANTIATE_TEST_SUITE_P(
@@ -196,6 +179,7 @@
::testing::Values(make_tuple("bbb_44100hz_2ch_128kbps_aac_30sec.mp4", "", true),
make_tuple("bbb_8000hz_1ch_8kbps_amrnb_30sec.3gp", "", true),
make_tuple("bbb_16000hz_1ch_9kbps_amrwb_30sec.3gp", "", true),
+ make_tuple("bbb_44100hz_2ch_600kbps_flac_30sec.mp4", "", true),
make_tuple("bbb_48000hz_2ch_100kbps_opus_30sec.webm", "", true)));
INSTANTIATE_TEST_SUITE_P(VideEncoderSyncTest, EncoderTest,
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 2dbc476..c0967d9 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -30,6 +30,7 @@
],
shared_libs: [
"libbinder",
+ "libcutils",
"liblog",
"libutils",
"libhidlbase",
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index db13903..02141a8 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -63,7 +63,10 @@
uid_t uid, bool start) {
// Okay to not track in app ops as audio server is us and if
// device is rooted security model is considered compromised.
- if (isAudioServerOrRootUid(uid)) return true;
+ // system_server loses its RECORD_AUDIO permission when a secondary
+ // user is active, but it is a core system service so let it through.
+ // TODO(b/141210120): UserManager.DISALLOW_RECORD_AUDIO should not affect system user 0
+ if (isAudioServerOrSystemServerOrRootUid(uid)) return true;
// We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
// may open a record track on behalf of a client. Note that pid may be a tid.
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 2a6e609..e1089d5 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -58,6 +58,12 @@
return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER;
}
+// used for calls that should come from system_server or audio_server and
+// include AID_ROOT for command-line tests.
+static inline bool isAudioServerOrSystemServerOrRootUid(uid_t uid) {
+ return multiuser_get_app_id(uid) == AID_SYSTEM || uid == AID_AUDIOSERVER || uid == AID_ROOT;
+}
+
// Mediaserver may forward the client PID and UID as part of a binder interface call;
// otherwise the calling UID must be equal to the client UID.
static inline bool isAudioServerOrMediaServerUid(uid_t uid) {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 355d945..4b295c9 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -810,7 +810,33 @@
continue;
}
- size_t frameCount = std::lcm(thread->frameCount(), secondaryThread->frameCount());
+ size_t sourceFrameCount = thread->frameCount() * output.sampleRate
+ / thread->sampleRate();
+ size_t sinkFrameCount = secondaryThread->frameCount() * output.sampleRate
+ / secondaryThread->sampleRate();
+ // If the secondary output has just been opened, the first secondaryThread write
+ // will not block as it will fill the empty startup buffer of the HAL,
+ // so a second sink buffer needs to be ready for the immediate next blocking write.
+ // Additionally, have a margin of one main thread buffer as the scheduling jitter
+ // can reorder the writes (eg if thread A&B have the same write intervale,
+ // the scheduler could schedule AB...BA)
+ size_t frameCountToBeReady = 2 * sinkFrameCount + sourceFrameCount;
+ // Total secondary output buffer must be at least as the read frames plus
+ // the margin of a few buffers on both sides in case the
+ // threads scheduling has some jitter.
+ // That value should not impact latency as the secondary track is started before
+ // its buffer is full, see frameCountToBeReady.
+ size_t frameCount = frameCountToBeReady + 2 * (sourceFrameCount + sinkFrameCount);
+ // The frameCount should also not be smaller than the secondary thread min frame
+ // count
+ size_t minFrameCount = AudioSystem::calculateMinFrameCount(
+ [&] { Mutex::Autolock _l(secondaryThread->mLock);
+ return secondaryThread->latency_l(); }(),
+ secondaryThread->mNormalFrameCount,
+ secondaryThread->mSampleRate,
+ output.sampleRate,
+ input.speed);
+ frameCount = std::max(frameCount, minFrameCount);
using namespace std::chrono_literals;
auto inChannelMask = audio_channel_mask_out_to_in(input.config.channel_mask);
@@ -843,7 +869,8 @@
patchRecord->buffer(),
patchRecord->bufferSize(),
outputFlags,
- 0ns /* timeout */);
+ 0ns /* timeout */,
+ frameCountToBeReady);
status = patchTrack->initCheck();
if (status != NO_ERROR) {
ALOGE("Secondary output patchTrack init failed: %d", status);
@@ -1933,7 +1960,8 @@
&output.notificationFrameCount,
callingPid, clientUid, &output.flags,
input.clientInfo.clientTid,
- &lStatus, portId);
+ &lStatus, portId,
+ input.opPackageName);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
// lStatus == BAD_TYPE means FAST flag was rejected: request a new input from
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 3c4fbba..13152d0 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -24,6 +24,7 @@
#include "Configuration.h"
#include <utils/Log.h>
#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_dynamicsprocessing.h>
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_visualizer.h>
#include <audio_utils/channels.h>
@@ -2569,7 +2570,8 @@
if ((mSessionId == AUDIO_SESSION_OUTPUT_MIX) &&
(((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) ||
(memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) ||
- (memcmp(&desc.type, SL_IID_VOLUME, sizeof(effect_uuid_t)) == 0))) {
+ (memcmp(&desc.type, SL_IID_VOLUME, sizeof(effect_uuid_t)) == 0) ||
+ (memcmp(&desc.type, SL_IID_DYNAMICSPROCESSING, sizeof(effect_uuid_t)) == 0))) {
return false;
}
return true;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index d0f8b17..1ff03c4 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -74,7 +74,10 @@
uid_t uid,
audio_output_flags_t flags,
track_type type,
- audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
+ /** default behaviour is to start when there are as many frames
+ * ready as possible (aka. Buffer is full). */
+ size_t frameCountToBeReady = SIZE_MAX);
virtual ~Track();
virtual status_t initCheck() const;
@@ -263,6 +266,8 @@
};
sp<AudioVibrationController> mAudioVibrationController;
sp<os::ExternalVibration> mExternalVibration;
+ /** How many frames should be in the buffer before the track is considered ready */
+ const size_t mFrameCountToBeReady;
private:
void interceptBuffer(const AudioBufferProvider::Buffer& buffer);
@@ -382,7 +387,11 @@
void *buffer,
size_t bufferSize,
audio_output_flags_t flags,
- const Timeout& timeout = {});
+ const Timeout& timeout = {},
+ size_t frameCountToBeReady = 1 /** Default behaviour is to start
+ * as soon as possible to have
+ * the lowest possible latency
+ * even if it might glitch. */);
virtual ~PatchTrack();
size_t framesReady() const override;
@@ -402,5 +411,4 @@
private:
void restartIfDisabled();
-
}; // end of PatchTrack
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index da05dac..d5257bd 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -19,6 +19,39 @@
#error This header file should only be included from AudioFlinger.h
#endif
+// Checks and monitors OP_RECORD_AUDIO
+class OpRecordAudioMonitor : public RefBase {
+public:
+ ~OpRecordAudioMonitor() override;
+ bool hasOpRecordAudio() const;
+
+ static sp<OpRecordAudioMonitor> createIfNeeded(uid_t uid, const String16& opPackageName);
+
+private:
+ OpRecordAudioMonitor(uid_t uid, const String16& opPackageName);
+ void onFirstRef() override;
+
+ AppOpsManager mAppOpsManager;
+
+ class RecordAudioOpCallback : public BnAppOpsCallback {
+ public:
+ explicit RecordAudioOpCallback(const wp<OpRecordAudioMonitor>& monitor);
+ void opChanged(int32_t op, const String16& packageName) override;
+
+ private:
+ const wp<OpRecordAudioMonitor> mMonitor;
+ };
+
+ sp<RecordAudioOpCallback> mOpCallback;
+ // called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback
+ // and in onFirstRef()
+ void checkRecordAudio();
+
+ std::atomic_bool mHasOpRecordAudio;
+ const uid_t mUid;
+ const String16 mPackage;
+};
+
// record track
class RecordTrack : public TrackBase {
public:
@@ -36,6 +69,7 @@
uid_t uid,
audio_input_flags_t flags,
track_type type,
+ const String16& opPackageName,
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE);
virtual ~RecordTrack();
virtual status_t initCheck() const;
@@ -68,7 +102,7 @@
{ return (mFlags & AUDIO_INPUT_FLAG_DIRECT) != 0; }
void setSilenced(bool silenced) { if (!isPatchTrack()) mSilenced = silenced; }
- bool isSilenced() const { return mSilenced; }
+ bool isSilenced() const;
status_t getActiveMicrophones(std::vector<media::MicrophoneInfo>* activeMicrophones);
@@ -111,6 +145,11 @@
audio_input_flags_t mFlags;
bool mSilenced;
+
+ // used to enforce OP_RECORD_AUDIO
+ uid_t mUid;
+ String16 mOpPackageName;
+ sp<OpRecordAudioMonitor> mOpRecordAudioMonitor;
};
// playback track, used by PatchPanel
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 2d769cf..ac892a5 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2953,9 +2953,11 @@
ALOG_ASSERT(mCallbackThread != 0);
mCallbackThread->setWriteBlocked(mWriteAckSequence);
}
+ ATRACE_BEGIN("write");
// FIXME We should have an implementation of timestamps for direct output threads.
// They are used e.g for multichannel PCM playback over HDMI.
bytesWritten = mOutput->write((char *)mSinkBuffer + offset, mBytesRemaining);
+ ATRACE_END();
if (mUseAsyncWrite &&
((bytesWritten < 0) || (bytesWritten == (ssize_t)mBytesRemaining))) {
@@ -3956,6 +3958,32 @@
return INVALID_OPERATION;
}
+// For dedicated VoIP outputs, let the HAL apply the stream volume. Track volume is
+// still applied by the mixer.
+// All tracks attached to a mixer with flag VOIP_RX are tied to the same
+// stream type STREAM_VOICE_CALL so this will only change the HAL volume once even
+// if more than one track are active
+status_t AudioFlinger::PlaybackThread::handleVoipVolume_l(float *volume)
+{
+ status_t result = NO_ERROR;
+ if ((mOutput->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) != 0) {
+ if (*volume != mLeftVolFloat) {
+ result = mOutput->stream->setVolume(*volume, *volume);
+ ALOGE_IF(result != OK,
+ "Error when setting output stream volume: %d", result);
+ if (result == NO_ERROR) {
+ mLeftVolFloat = *volume;
+ }
+ }
+ // if stream volume was successfully sent to the HAL, mLeftVolFloat == v here and we
+ // remove stream volume contribution from software volume.
+ if (mLeftVolFloat == *volume) {
+ *volume = 1.0f;
+ }
+ }
+ return result;
+}
+
status_t AudioFlinger::MixerThread::createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle)
{
@@ -4758,22 +4786,25 @@
// no acknowledgement required for newly active tracks
}
sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
+ float volume;
+ if (track->isPlaybackRestricted() || mStreamTypes[track->streamType()].mute) {
+ volume = 0.f;
+ } else {
+ volume = masterVolume * mStreamTypes[track->streamType()].volume;
+ }
+
+ handleVoipVolume_l(&volume);
+
// cache the combined master volume and stream type volume for fast mixer; this
// lacks any synchronization or barrier so VolumeProvider may read a stale value
const float vh = track->getVolumeHandler()->getVolume(
- proxy->framesReleased()).first;
- float volume;
- if (track->isPlaybackRestricted()) {
- volume = 0.f;
- } else {
- volume = masterVolume
- * mStreamTypes[track->streamType()].volume
- * vh;
- }
+ proxy->framesReleased()).first;
+ volume *= vh;
track->mCachedVolume = volume;
gain_minifloat_packed_t vlr = proxy->getVolumeLR();
float vlf = volume * float_from_gain(gain_minifloat_unpack_left(vlr));
float vrf = volume * float_from_gain(gain_minifloat_unpack_right(vlr));
+
track->setFinalVolume((vlf + vrf) / 2.f);
++fastTracks;
} else {
@@ -4916,20 +4947,22 @@
uint32_t vl, vr; // in U8.24 integer format
float vlf, vrf, vaf; // in [0.0, 1.0] float format
// read original volumes with volume control
- float typeVolume = mStreamTypes[track->streamType()].volume;
- float v = masterVolume * typeVolume;
+ float v = masterVolume * mStreamTypes[track->streamType()].volume;
// Always fetch volumeshaper volume to ensure state is updated.
const sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
const float vh = track->getVolumeHandler()->getVolume(
track->mAudioTrackServerProxy->framesReleased()).first;
- if (track->isPausing() || mStreamTypes[track->streamType()].mute
- || track->isPlaybackRestricted()) {
+ if (mStreamTypes[track->streamType()].mute || track->isPlaybackRestricted()) {
+ v = 0;
+ }
+
+ handleVoipVolume_l(&v);
+
+ if (track->isPausing()) {
vl = vr = 0;
vlf = vrf = vaf = 0.;
- if (track->isPausing()) {
- track->setPaused();
- }
+ track->setPaused();
} else {
gain_minifloat_packed_t vlr = proxy->getVolumeLR();
vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
@@ -4981,25 +5014,6 @@
track->mHasVolumeController = false;
}
- // For dedicated VoIP outputs, let the HAL apply the stream volume. Track volume is
- // still applied by the mixer.
- if ((mOutput->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) != 0) {
- v = mStreamTypes[track->streamType()].mute ? 0.0f : v;
- if (v != mLeftVolFloat) {
- status_t result = mOutput->stream->setVolume(v, v);
- ALOGE_IF(result != OK, "Error when setting output stream volume: %d", result);
- if (result == OK) {
- mLeftVolFloat = v;
- }
- }
- // if stream volume was successfully sent to the HAL, mLeftVolFloat == v here and we
- // remove stream volume contribution from software volume.
- if (v != 0.0f && mLeftVolFloat == v) {
- vlf = min(1.0f, vlf / v);
- vrf = min(1.0f, vrf / v);
- vaf = min(1.0f, vaf / v);
- }
- }
// XXX: these things DON'T need to be done each time
mAudioMixer->setBufferProvider(trackId, track);
mAudioMixer->enable(trackId);
@@ -5646,10 +5660,17 @@
minFrames = 1;
}
- if ((track->framesReady() >= minFrames) && track->isReady() && !track->isPaused() &&
+ const size_t framesReady = track->framesReady();
+ const int trackId = track->id();
+ if (ATRACE_ENABLED()) {
+ std::string traceName("nRdy");
+ traceName += std::to_string(trackId);
+ ATRACE_INT(traceName.c_str(), framesReady);
+ }
+ if ((framesReady >= minFrames) && track->isReady() && !track->isPaused() &&
!track->isStopping_2() && !track->isStopped())
{
- ALOGVV("track(%d) s=%08x [OK]", track->id(), cblk->mServer);
+ ALOGVV("track(%d) s=%08x [OK]", trackId, cblk->mServer);
if (track->mFillingUpStatus == Track::FS_FILLED) {
track->mFillingUpStatus = Track::FS_ACTIVE;
@@ -5726,7 +5747,7 @@
// fill a buffer, then remove it from active list.
// Only consider last track started for mixer state control
if (--(track->mRetryCount) <= 0) {
- ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", track->id());
+ ALOGV("BUFFER TIMEOUT: remove track(%d) from active list", trackId);
tracksToRemove->add(track);
// indicate to client process that the track was disabled because of underrun;
// it will then automatically call start() when data is available
@@ -5734,7 +5755,7 @@
} else if (last) {
ALOGW("pause because of UNDERRUN, framesReady = %zu,"
"minFrames = %u, mFormat = %#x",
- track->framesReady(), minFrames, mFormat);
+ framesReady, minFrames, mFormat);
mixerStatus = MIXER_TRACKS_ENABLED;
if (mHwSupportsPause && !mHwPaused && !mStandby) {
doHwPause = true;
@@ -7282,7 +7303,7 @@
// Sanitize before releasing if the track has no access to the source data
// An idle UID receives silence from non virtual devices until active
if (activeTrack->isSilenced()) {
- memset(activeTrack->mSink.raw, 0, framesOut * mFrameSize);
+ memset(activeTrack->mSink.raw, 0, framesOut * activeTrack->frameSize());
}
activeTrack->releaseBuffer(&activeTrack->mSink);
}
@@ -7443,7 +7464,8 @@
audio_input_flags_t *flags,
pid_t tid,
status_t *status,
- audio_port_handle_t portId)
+ audio_port_handle_t portId,
+ const String16& opPackageName)
{
size_t frameCount = *pFrameCount;
size_t notificationFrameCount = *pNotificationFrameCount;
@@ -7577,7 +7599,7 @@
track = new RecordTrack(this, client, attr, sampleRate,
format, channelMask, frameCount,
nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, creatorPid, uid,
- *flags, TrackBase::TYPE_DEFAULT, portId);
+ *flags, TrackBase::TYPE_DEFAULT, opPackageName, portId);
lStatus = track->initCheck();
if (lStatus != NO_ERROR) {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 31e10a3..0a473d5 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -747,6 +747,7 @@
// is safe to do so. That will drop the final ref count and destroy the tracks.
virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove) = 0;
void removeTracks_l(const Vector< sp<Track> >& tracksToRemove);
+ status_t handleVoipVolume_l(float *volume);
// StreamOutHalInterfaceCallback implementation
virtual void onWriteReady();
@@ -1552,7 +1553,8 @@
audio_input_flags_t *flags,
pid_t tid,
status_t *status /*non-NULL*/,
- audio_port_handle_t portId);
+ audio_port_handle_t portId,
+ const String16& opPackageName);
status_t start(RecordTrack* recordTrack,
AudioSystem::sync_event_t event,
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 7a3bb0d..52e7d59 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -215,6 +215,8 @@
uint32_t channelCount() const { return mChannelCount; }
+ size_t frameSize() const { return mFrameSize; }
+
audio_channel_mask_t channelMask() const { return mChannelMask; }
virtual uint32_t sampleRate() const { return mSampleRate; }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 932c32b..e4402bd 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -444,7 +444,7 @@
return mHasOpPlayAudio.load();
}
-// Note this method is never called (and never to be) for audio server / root track
+// Note this method is never called (and never to be) for audio server / patch record track
// - not called from constructor due to check on UID,
// - not called from PlayAudioOpCallback because the callback is not installed in this case
void AudioFlinger::PlaybackThread::OpPlayAudioMonitor::checkPlayAudioForUsage()
@@ -513,7 +513,8 @@
uid_t uid,
audio_output_flags_t flags,
track_type type,
- audio_port_handle_t portId)
+ audio_port_handle_t portId,
+ size_t frameCountToBeReady)
: TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
(sharedBuffer != 0) ? sharedBuffer->pointer() : buffer,
(sharedBuffer != 0) ? sharedBuffer->size() : bufferSize,
@@ -532,6 +533,7 @@
mVolumeHandler(new media::VolumeHandler(sampleRate)),
mOpPlayAudioMonitor(OpPlayAudioMonitor::createIfNeeded(uid, attr, id(), streamType)),
// mSinkTimestamp
+ mFrameCountToBeReady(frameCountToBeReady),
mFastIndex(-1),
mCachedVolume(1.0),
/* The track might not play immediately after being active, similarly as if its volume was 0.
@@ -832,7 +834,7 @@
auto spent = ceil<std::chrono::microseconds>(std::chrono::steady_clock::now() - start);
using namespace std::chrono_literals;
// Average is ~20us per track, this should virtually never be logged (Logging takes >200us)
- ALOGD_IF(spent > 200us, "%s: took %lldus to intercept %zu tracks", __func__,
+ ALOGD_IF(spent > 500us, "%s: took %lldus to intercept %zu tracks", __func__,
spent.count(), mTeePatches.size());
}
@@ -885,8 +887,12 @@
return true;
}
- if (framesReady() >= mServerProxy->getBufferSizeInFrames() ||
- (mCblk->mFlags & CBLK_FORCEREADY)) {
+ size_t bufferSizeInFrames = mServerProxy->getBufferSizeInFrames();
+ size_t framesToBeReady = std::min(mFrameCountToBeReady, bufferSizeInFrames);
+
+ if (framesReady() >= framesToBeReady || (mCblk->mFlags & CBLK_FORCEREADY)) {
+ ALOGV("%s(%d): consider track ready with %zu/%zu, target was %zu)",
+ __func__, mId, framesReady(), bufferSizeInFrames, framesToBeReady);
mFillingUpStatus = FS_FILLED;
android_atomic_and(~CBLK_FORCEREADY, &mCblk->mFlags);
return true;
@@ -1388,6 +1394,7 @@
void AudioFlinger::PlaybackThread::Track::disable()
{
+ // TODO(b/142394888): the filling status should also be reset to filling
signalClientFlag(CBLK_DISABLED);
}
@@ -1765,12 +1772,14 @@
void *buffer,
size_t bufferSize,
audio_output_flags_t flags,
- const Timeout& timeout)
+ const Timeout& timeout,
+ size_t frameCountToBeReady)
: Track(playbackThread, NULL, streamType,
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
buffer, bufferSize, nullptr /* sharedBuffer */,
- AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH),
+ AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER, flags, TYPE_PATCH,
+ AUDIO_PORT_HANDLE_NONE, frameCountToBeReady),
PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, true, true),
*playbackThread, timeout)
{
@@ -1863,7 +1872,6 @@
{
mProxy->releaseBuffer(buffer);
restartIfDisabled();
- android_atomic_or(CBLK_FORCEREADY, &mCblk->mFlags);
}
void AudioFlinger::PlaybackThread::PatchTrack::restartIfDisabled()
@@ -1877,6 +1885,105 @@
// ----------------------------------------------------------------------------
// Record
// ----------------------------------------------------------------------------
+
+
+// ----------------------------------------------------------------------------
+// AppOp for audio recording
+// -------------------------------
+
+#undef LOG_TAG
+#define LOG_TAG "AF::OpRecordAudioMonitor"
+
+// static
+sp<AudioFlinger::RecordThread::OpRecordAudioMonitor>
+AudioFlinger::RecordThread::OpRecordAudioMonitor::createIfNeeded(
+ uid_t uid, const String16& opPackageName)
+{
+ if (isServiceUid(uid)) {
+ ALOGV("not silencing record for service uid:%d pack:%s",
+ uid, String8(opPackageName).string());
+ return nullptr;
+ }
+
+ if (opPackageName.size() == 0) {
+ Vector<String16> packages;
+ // no package name, happens with SL ES clients
+ // query package manager to find one
+ PermissionController permissionController;
+ permissionController.getPackagesForUid(uid, packages);
+ if (packages.isEmpty()) {
+ return nullptr;
+ } else {
+ ALOGV("using pack:%s for uid:%d", String8(packages[0]).string(), uid);
+ return new OpRecordAudioMonitor(uid, packages[0]);
+ }
+ }
+
+ return new OpRecordAudioMonitor(uid, opPackageName);
+}
+
+AudioFlinger::RecordThread::OpRecordAudioMonitor::OpRecordAudioMonitor(
+ uid_t uid, const String16& opPackageName)
+ : mHasOpRecordAudio(true), mUid(uid), mPackage(opPackageName)
+{
+}
+
+AudioFlinger::RecordThread::OpRecordAudioMonitor::~OpRecordAudioMonitor()
+{
+ if (mOpCallback != 0) {
+ mAppOpsManager.stopWatchingMode(mOpCallback);
+ }
+ mOpCallback.clear();
+}
+
+void AudioFlinger::RecordThread::OpRecordAudioMonitor::onFirstRef()
+{
+ checkRecordAudio();
+ mOpCallback = new RecordAudioOpCallback(this);
+ ALOGV("start watching OP_RECORD_AUDIO for pack:%s", String8(mPackage).string());
+ mAppOpsManager.startWatchingMode(AppOpsManager::OP_RECORD_AUDIO, mPackage, mOpCallback);
+}
+
+bool AudioFlinger::RecordThread::OpRecordAudioMonitor::hasOpRecordAudio() const {
+ return mHasOpRecordAudio.load();
+}
+
+// Called by RecordAudioOpCallback when OP_RECORD_AUDIO is updated in AppOp callback
+// and in onFirstRef()
+// Note this method is never called (and never to be) for audio server / root track
+// due to the UID in createIfNeeded(). As a result for those record track, it's:
+// - not called from constructor,
+// - not called from RecordAudioOpCallback because the callback is not installed in this case
+void AudioFlinger::RecordThread::OpRecordAudioMonitor::checkRecordAudio()
+{
+ const int32_t mode = mAppOpsManager.checkOp(AppOpsManager::OP_RECORD_AUDIO,
+ mUid, mPackage);
+ const bool hasIt = (mode == AppOpsManager::MODE_ALLOWED);
+ // verbose logging only log when appOp changed
+ ALOGI_IF(hasIt != mHasOpRecordAudio.load(),
+ "OP_RECORD_AUDIO missing, %ssilencing record uid%d pack:%s",
+ hasIt ? "un" : "", mUid, String8(mPackage).string());
+ mHasOpRecordAudio.store(hasIt);
+}
+
+AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::RecordAudioOpCallback(
+ const wp<OpRecordAudioMonitor>& monitor) : mMonitor(monitor)
+{ }
+
+void AudioFlinger::RecordThread::OpRecordAudioMonitor::RecordAudioOpCallback::opChanged(int32_t op,
+ const String16& packageName) {
+ UNUSED(packageName);
+ if (op != AppOpsManager::OP_RECORD_AUDIO) {
+ return;
+ }
+ sp<OpRecordAudioMonitor> monitor = mMonitor.promote();
+ if (monitor != NULL) {
+ monitor->checkRecordAudio();
+ }
+}
+
+
+
#undef LOG_TAG
#define LOG_TAG "AF::RecordHandle"
@@ -1948,6 +2055,7 @@
uid_t uid,
audio_input_flags_t flags,
track_type type,
+ const String16& opPackageName,
audio_port_handle_t portId)
: TrackBase(thread, client, attr, sampleRate, format,
channelMask, frameCount, buffer, bufferSize, sessionId,
@@ -1961,7 +2069,8 @@
mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
mRecordBufferConverter(NULL),
mFlags(flags),
- mSilenced(false)
+ mSilenced(false),
+ mOpRecordAudioMonitor(OpRecordAudioMonitor::createIfNeeded(uid, opPackageName))
{
if (mCblk == NULL) {
return;
@@ -2212,6 +2321,14 @@
mServerLatencyMs.store(latencyMs);
}
+bool AudioFlinger::RecordThread::RecordTrack::isSilenced() const {
+ if (mSilenced) {
+ return true;
+ }
+ // The monitor is only created for record tracks that can be silenced.
+ return mOpRecordAudioMonitor ? !mOpRecordAudioMonitor->hasOpRecordAudio() : false;
+}
+
status_t AudioFlinger::RecordThread::RecordTrack::getActiveMicrophones(
std::vector<media::MicrophoneInfo>* activeMicrophones)
{
@@ -2262,7 +2379,7 @@
audio_attributes_t{} /* currently unused for patch track */,
sampleRate, format, channelMask, frameCount,
buffer, bufferSize, AUDIO_SESSION_NONE, getpid(), AID_AUDIOSERVER,
- flags, TYPE_PATCH),
+ flags, TYPE_PATCH, String16()),
PatchTrackBase(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true),
*recordThread, timeout)
{
@@ -2414,7 +2531,6 @@
if (!stream) return NO_INIT; // If there is no stream, RecordThread is not reading.
status_t result = NO_ERROR;
- struct timespec newTimeOut = *timeOut;
size_t bytesRead = 0;
{
ATRACE_NAME("read");
@@ -2437,15 +2553,16 @@
ALOGW_IF(buffer->mFrameCount < bytesRead / mFrameSize,
"Lost %zu frames obtained from HAL", bytesRead / mFrameSize - buffer->mFrameCount);
mUnconsumedFrames = buffer->mFrameCount;
- // Correct newTimeOut by elapsed time.
+ struct timespec newTimeOut;
if (startTimeNs) {
- nsecs_t newTimeOutNs =
- audio_utils_ns_from_timespec(&newTimeOut) - (systemTime() - startTimeNs);
+ // Correct the timeout by elapsed time.
+ nsecs_t newTimeOutNs = audio_utils_ns_from_timespec(timeOut) - (systemTime() - startTimeNs);
if (newTimeOutNs < 0) newTimeOutNs = 0;
newTimeOut.tv_sec = newTimeOutNs / NANOS_PER_SECOND;
newTimeOut.tv_nsec = newTimeOutNs - newTimeOut.tv_sec * NANOS_PER_SECOND;
+ timeOut = &newTimeOut;
}
- return PatchRecord::obtainBuffer(buffer, &newTimeOut);
+ return PatchRecord::obtainBuffer(buffer, timeOut);
stream_error:
stream->standby();
diff --git a/services/audiopolicy/config/Android.bp b/services/audiopolicy/config/Android.bp
new file mode 100644
index 0000000..4b5e788
--- /dev/null
+++ b/services/audiopolicy/config/Android.bp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+
+soong_namespace {
+}
+
+prebuilt_etc {
+ name: "a2dp_in_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":a2dp_in_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "a2dp_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":a2dp_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "audio_policy_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_configuration_generic",
+}
+prebuilt_etc {
+ name: "r_submix_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":r_submix_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "audio_policy_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_volumes",
+}
+prebuilt_etc {
+ name: "default_volume_tables.xml",
+ vendor: true,
+ src: ":default_volume_tables",
+}
+prebuilt_etc {
+ name: "surround_sound_configuration_5_0.xml",
+ vendor: true,
+ src: ":surround_sound_configuration_5_0",
+}
+prebuilt_etc {
+ name: "usb_audio_policy_configuration.xml",
+ vendor: true,
+ src: ":usb_audio_policy_configuration",
+}
+prebuilt_etc {
+ name: "primary_audio_policy_configuration.xml",
+ src: ":primary_audio_policy_configuration",
+ vendor: true,
+}
+
+filegroup {
+ name: "a2dp_in_audio_policy_configuration",
+ srcs: ["a2dp_in_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "a2dp_audio_policy_configuration",
+ srcs: ["a2dp_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "primary_audio_policy_configuration",
+ srcs: ["primary_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "surround_sound_configuration_5_0",
+ srcs: ["surround_sound_configuration_5_0.xml"],
+}
+filegroup {
+ name: "default_volume_tables",
+ srcs: ["default_volume_tables.xml"],
+}
+filegroup {
+ name: "audio_policy_volumes",
+ srcs: ["audio_policy_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_configuration_generic",
+ srcs: ["audio_policy_configuration_generic.xml"],
+}
+filegroup {
+ name: "usb_audio_policy_configuration",
+ srcs: ["usb_audio_policy_configuration.xml"],
+}
+filegroup {
+ name: "r_submix_audio_policy_configuration",
+ srcs: ["r_submix_audio_policy_configuration.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/Android.bp b/services/audiopolicy/engineconfigurable/config/Android.bp
new file mode 100644
index 0000000..fe3eae0
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/Android.bp
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+// Root soong_namespace for common components
+
+prebuilt_etc {
+ name: "audio_policy_engine_criteria.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criteria",
+}
+filegroup {
+ name: "audio_policy_engine_criterion_types_template",
+ srcs: ["example/common/audio_policy_engine_criterion_types.xml.in"],
+}
+filegroup {
+ name: "audio_policy_engine_criteria",
+ srcs: ["example/common/audio_policy_engine_criteria.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/Android.mk b/services/audiopolicy/engineconfigurable/config/example/Android.mk
deleted file mode 100644
index a0f1a90..0000000
--- a/services/audiopolicy/engineconfigurable/config/example/Android.mk
+++ /dev/null
@@ -1,151 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-PROVISION_CRITERION_TYPES := $(TOOLS)/provision_criterion_types_from_android_headers.mk
-
-##################################################################
-# CONFIGURATION TOP FILE
-##################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration.xml
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-
-LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies.xml \
- audio_policy_engine_stream_volumes.xml \
- audio_policy_engine_default_stream_volumes.xml \
- audio_policy_engine_criteria.xml \
- audio_policy_engine_criterion_types.xml
-
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_default_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
-
-##################################################################
-# AUTOMOTIVE CONFIGURATION TOP FILE
-##################################################################
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
-
-LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies.xml \
- audio_policy_engine_criteria.xml \
- audio_policy_engine_criterion_types.xml \
- audio_policy_engine_volumes.xml
-
-include $(BUILD_PREBUILT)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),automotive_configurable caremu_configurable))
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := automotive/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := caremu/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := caremu/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_criteria.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := common/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_criterion_types.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_VENDOR_ETC)/primary_audio_policy_configuration.xml
-ANDROID_AUDIO_BASE_HEADER_FILE := system/media/audio/include/system/audio-base.h
-AUDIO_POLICY_CONFIGURATION_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_configuration.xml
-CRITERION_TYPES_FILE := $(LOCAL_PATH)/common/$(LOCAL_MODULE).in
-
-include $(PROVISION_CRITERION_TYPES)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-endif #ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
diff --git a/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp b/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp
new file mode 100644
index 0000000..f913a14
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/automotive/Android.bp
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Automotive configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_engine_configuration",
+ required: [
+ ":audio_policy_engine_criterion_types.xml",
+ ":audio_policy_engine_criteria.xml",
+ ":audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_engine_volumes",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_criterion_types.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criterion_types",
+}
+
+//
+// Generate audio_policy_engine criterion type file => provides device addresses criterion type
+//
+genrule {
+ name: "audio_policy_engine_criterion_types",
+ defaults: ["buildpolicycriteriontypesrule"],
+ srcs: [
+ ":audio_policy_configuration_top_file",
+ ":audio_policy_configuration_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_configuration_files",
+ srcs: [
+ ":r_submix_audio_policy_configuration",
+ ":default_volume_tables",
+ ":audio_policy_volumes",
+ ":surround_sound_configuration_5_0",
+ ":primary_audio_policy_configuration",
+ ],
+}
+filegroup {
+ name : "audio_policy_configuration_top_file",
+ srcs: [":audio_policy_configuration_generic"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration",
+ srcs: ["audio_policy_engine_configuration.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_volumes",
+ srcs: ["audio_policy_engine_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration_files",
+ srcs: [
+ ":audio_policy_engine_configuration",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes",
+ ":audio_policy_engine_criterion_types",
+ ":audio_policy_engine_criteria",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp b/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp
new file mode 100644
index 0000000..fae6b7b
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/caremu/Android.bp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Car Emulator configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_engine_configuration",
+ required: [
+ "audio_policy_engine_criterion_types.xml",
+ "audio_policy_engine_criteria.xml",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_criterion_types.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criterion_types",
+}
+
+//
+// Generate audio_policy_engine criterion type file => provides device addresses criterion type
+//
+genrule {
+ name: "audio_policy_engine_criterion_types",
+ defaults: ["buildpolicycriteriontypesrule"],
+ srcs: [
+ ":audio_policy_configuration_top_file",
+ ":audio_policy_configuration_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_configuration_files",
+ srcs: [
+ ":r_submix_audio_policy_configuration",
+ ":default_volume_tables",
+ ":audio_policy_volumes",
+ ":surround_sound_configuration_5_0",
+ ":primary_audio_policy_configuration",
+ ],
+}
+filegroup {
+ name : "audio_policy_configuration_top_file",
+ srcs: [":audio_policy_configuration_generic"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration_files",
+ srcs: [
+ ":audio_policy_engine_configuration",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes",
+ ":audio_policy_engine_criterion_types",
+ ":audio_policy_engine_criteria",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp b/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp
new file mode 100644
index 0000000..94d33bd
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/phone/Android.bp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Phone configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: ":audio_policy_engine_configuration",
+ required: [
+ ":audio_policy_engine_criterion_types.xml",
+ ":audio_policy_engine_criteria.xml",
+ ":audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_volumes.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_stream_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_engine_stream_volumes",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_default_stream_volumes.xml",
+ vendor: true,
+ src: ":audio_policy_engine_default_stream_volumes",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_criterion_types.xml",
+ vendor: true,
+ src: ":audio_policy_engine_criterion_types",
+}
+
+//
+// Generate audio_policy_engine criterion type file => provides device addresses criterion type
+//
+genrule {
+ name: "audio_policy_engine_criterion_types",
+ defaults: ["buildpolicycriteriontypesrule"],
+ srcs: [
+ ":audio_policy_configuration_top_file",
+ ":audio_policy_configuration_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_configuration_files",
+ srcs: [
+ ":r_submix_audio_policy_configuration",
+ ":default_volume_tables",
+ ":audio_policy_volumes",
+ ":surround_sound_configuration_5_0",
+ ":primary_audio_policy_configuration",
+ ],
+}
+filegroup {
+ name : "audio_policy_configuration_top_file",
+ srcs: [":audio_policy_configuration_generic"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration",
+ srcs: ["audio_policy_engine_configuration.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_stream_volumes",
+ srcs: ["audio_policy_engine_stream_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_default_stream_volumes",
+ srcs: ["audio_policy_engine_default_stream_volumes.xml"],
+}
+filegroup {
+ name: "audio_policy_engine_configuration_files",
+ srcs: [
+ ":audio_policy_engine_configuration",
+ "audio_policy_engine_product_strategies.xml",
+ ":audio_policy_engine_stream_volumes",
+ ":audio_policy_engine_default_stream_volumes",
+ ":audio_policy_engine_criterion_types",
+ ":audio_policy_engine_criteria",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
new file mode 100644
index 0000000..a0b874a
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Root soong_namespace for common components
+
+prebuilt_etc {
+ name: "PolicyClass.xml",
+ vendor: true,
+ src: ":PolicyClass",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+prebuilt_etc {
+ name: "PolicySubsystem.xml",
+ vendor: true,
+ src: ":PolicySubsystem",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+prebuilt_etc {
+ name: "PolicySubsystem-CommonTypes.xml",
+ vendor: true,
+ src: ":PolicySubsystem-CommonTypes",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+
+filegroup {
+ name: "product_strategies_structure_template",
+ srcs: ["examples/common/Structure/ProductStrategies.xml.in"],
+}
+filegroup {
+ name: "PolicySubsystem",
+ srcs: ["examples/common/Structure/PolicySubsystem.xml"],
+}
+filegroup {
+ name: "PolicySubsystem-no-strategy",
+ srcs: ["examples/common/Structure/PolicySubsystem-no-strategy.xml"],
+}
+filegroup {
+ name: "PolicySubsystem-CommonTypes",
+ srcs: ["examples/common/Structure/PolicySubsystem-CommonTypes.xml"],
+}
+filegroup {
+ name: "PolicyClass",
+ srcs: ["examples/common/Structure/PolicyClass.xml"],
+}
+filegroup {
+ name: "volumes.pfw",
+ srcs: ["examples/Settings/volumes.pfw"],
+}
+filegroup {
+ name: "device_for_input_source.pfw",
+ srcs: ["examples/Settings/device_for_input_source.pfw"],
+}
+filegroup {
+ name: "ParameterFrameworkConfigurationPolicy.userdebug.xml",
+ srcs: ["examples/ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "ParameterFrameworkConfigurationPolicy.user.xml",
+ srcs: ["examples/ParameterFrameworkConfigurationPolicy.user.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
deleted file mode 100644
index 19f93b3..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Android.mk
+++ /dev/null
@@ -1,187 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-LOCAL_PATH := $(call my-dir)
-
-ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable no-output_configurable no-input_configurable))
-
-PFW_CORE := external/parameter-framework
-#@TODO: upstream new domain generator
-#BUILD_PFW_SETTINGS := $(PFW_CORE)/support/android/build_pfw_settings.mk
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-PROVISION_STRATEGIES_STRUCTURE := $(TOOLS)/provision_strategies_structure.mk
-
-endif
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-######### Policy PFW top level file #########
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ParameterFrameworkConfigurationPolicy.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework
-LOCAL_SRC_FILES := $(LOCAL_MODULE).in
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem.xml \
- PolicyClass.xml
-
-# external/parameter-framework prevents from using debug interface
-AUDIO_PATTERN = @TUNING_ALLOWED@
-ifeq ($(TARGET_BUILD_VARIANT),user)
-AUDIO_VALUE = false
-else
-AUDIO_VALUE = true
-endif
-
-LOCAL_POST_INSTALL_CMD := $(hide) sed -i -e 's|$(AUDIO_PATTERN)|$(AUDIO_VALUE)|g' $(TARGET_OUT_VENDOR_ETC)/$(LOCAL_MODULE_RELATIVE_PATH)/$(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
-
-########## Policy PFW Common Structures #########
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem-CommonTypes.xml \
- ProductStrategies.xml
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem-CommonTypes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicyClass.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ProductStrategies.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-
-AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := \
- $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_configuration.xml
-STRATEGIES_STRUCTURE_FILE := $(LOCAL_PATH)/common/Structure/$(LOCAL_MODULE).in
-
-include $(PROVISION_STRATEGIES_STRUCTURE)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),phone_configurable automotive_configurable caremu_configurable))
-
-########## Policy PFW Example Structures #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := PolicySubsystem.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_REQUIRED_MODULES := PolicySubsystem-CommonTypes.xml
-
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Structure/Policy
-LOCAL_SRC_FILES := common/Structure/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ParameterFrameworkConfigurationPolicy-no-strategy.xml
-LOCAL_MODULE_STEM := ParameterFrameworkConfigurationPolicy.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework
-LOCAL_SRC_FILES := $(LOCAL_MODULE).in
-LOCAL_REQUIRED_MODULES := \
- PolicySubsystem.xml \
- PolicyClass.xml
-AUDIO_VALUE = false
-LOCAL_POST_INSTALL_CMD := $(hide) sed -i -e 's|$(AUDIO_PATTERN)|$(AUDIO_VALUE)|g' $(TARGET_OUT_VENDOR_ETC)/$(LOCAL_MODULE_RELATIVE_PATH)/$(LOCAL_MODULE)
-
-include $(BUILD_PREBUILT)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),$(filter $(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable no-input_configurable))
-
-######### Policy PFW Settings - No Output #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoOutputDevice.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/SettingsNoOutput/device_for_strategies.pfw \
- $(LOCAL_PATH)/Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/Settings/volumes.pfw
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-include $(BUILD_PFW_SETTINGS)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-output_configurable)
-######### Policy PFW Settings - No Input #########
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains-NoInputDevice.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/SettingsNoInput/device_for_input_source.pfw \
- $(LOCAL_PATH)/Settings/volumes.pfw
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION),no-input_configurable)
-#######################################################################
-# Recursive call sub-folder Android.mk
-#######################################################################
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
-
-endif #ifdef BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION
-
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
new file mode 100644
index 0000000..5078268
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.bp
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Automotive configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/automotive",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Product Strategies Structure file from template
+//
+prebuilt_etc {
+ name: "ProductStrategies.xml",
+ vendor: true,
+ src: ":buildstrategiesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+ required: ["libpolicy-subsystem"],
+}
+genrule {
+ name: "buildstrategiesstructure_gen",
+ defaults: ["buildstrategiesstructurerule"],
+ srcs: [
+ ":audio_policy_engine_configuration_files",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Configurable Domains
+//
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "ProductStrategies.xml",
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ ":device_for_input_source.pfw",
+ ":volumes.pfw",
+ "Settings/device_for_product_strategies.pfw",
+ ],
+}
+// This is for Settings generation, must use socket port, so userdebug version is required
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ":buildstrategiesstructure_gen",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
deleted file mode 100644
index 7304ec2..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car/Android.mk
+++ /dev/null
@@ -1,47 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
-LOCAL_PATH := $(call my-dir)
-
-PFW_CORE := external/parameter-framework
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-########## Policy PFW Structures #########
-######### Policy PFW Settings #########
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
- $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/../Settings/volumes.pfw
-
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), automotive_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
new file mode 100644
index 0000000..0917440
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.bp
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Car Emulator configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/caremu",
+ "frameworks/av/services/audiopolicy/engineconfigurable/parameter-framework/examples/Car",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Product Strategies Structure file from template
+//
+prebuilt_etc {
+ name: "ProductStrategies.xml",
+ vendor: true,
+ src: ":buildstrategiesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+ required: ["libpolicy-subsystem"],
+}
+genrule {
+ name: "buildstrategiesstructure_gen",
+ defaults: ["buildstrategiesstructurerule"],
+ srcs: [
+ ":audio_policy_engine_configuration_files",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Configurable Domains
+//
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "ProductStrategies.xml",
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ ":device_for_input_source.pfw",
+ ":volumes.pfw",
+ "Settings/device_for_product_strategies.pfw",
+ ],
+}
+// This is for Settings generation, must use socket port, so userdebug version is required
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ":buildstrategiesstructure_gen",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
deleted file mode 100644
index f5eb7d1..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/CarEmu/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
-LOCAL_PATH := $(call my-dir)
-
-PFW_CORE := external/parameter-framework
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-
-########## Policy PFW Structures #########
-######### Policy PFW Settings #########
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/Settings/device_for_product_strategies.pfw \
- $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/../Settings/volumes.pfw
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), caremu_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.user.xml
similarity index 81%
copy from services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
copy to services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.user.xml
index 1be67dd..c5960cb 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.user.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- SystemClassName="Policy" ServerPort="unix:///dev/socket/audioserver/policy_debug"
- TuningAllowed="@TUNING_ALLOWED@">
+ SystemClassName="Policy" TuningAllowed="false">
<SubsystemPlugins>
<Location Folder="">
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.userdebug.xml
similarity index 93%
rename from services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
rename to services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.userdebug.xml
index 1be67dd..1b7d7d8 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.xml.in
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/ParameterFrameworkConfigurationPolicy.userdebug.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
SystemClassName="Policy" ServerPort="unix:///dev/socket/audioserver/policy_debug"
- TuningAllowed="@TUNING_ALLOWED@">
+ TuningAllowed="true">
<SubsystemPlugins>
<Location Folder="">
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
new file mode 100644
index 0000000..11e220b
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.bp
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP Phone configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Product Strategies Structure file from template
+//
+prebuilt_etc {
+ name: "ProductStrategies.xml",
+ vendor: true,
+ src: ":buildstrategiesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+ required: ["libpolicy-subsystem"],
+}
+genrule {
+ name: "buildstrategiesstructure_gen",
+ defaults: ["buildstrategiesstructurerule"],
+ srcs: [
+ ":audio_policy_engine_configuration_files",
+ ],
+}
+
+//
+// Generate Audio Policy Parameter Framework Configurable Domains
+//
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "ProductStrategies.xml",
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ ":device_for_input_source.pfw",
+ ":volumes.pfw",
+ "Settings/device_for_product_strategy_media.pfw",
+ "Settings/device_for_product_strategy_accessibility.pfw",
+ "Settings/device_for_product_strategy_dtmf.pfw",
+ "Settings/device_for_product_strategy_enforced_audible.pfw",
+ "Settings/device_for_product_strategy_phone.pfw",
+ "Settings/device_for_product_strategy_sonification.pfw",
+ "Settings/device_for_product_strategy_sonification_respectful.pfw",
+ "Settings/device_for_product_strategy_transmitted_through_speaker.pfw",
+ "Settings/device_for_product_strategy_rerouting.pfw",
+ "Settings/device_for_product_strategy_patch.pfw",
+ ],
+}
+// This is for Settings generation, must use socket port, so userdebug version is required
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ":buildstrategiesstructure_gen",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
deleted file mode 100644
index 0b20781..0000000
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Phone/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-################################################################################################
-#
-# @NOTE:
-# Audio Policy Engine configurable example for generic device build
-#
-# Any vendor shall have its own configuration within the corresponding device folder
-#
-################################################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
-
-LOCAL_PATH := $(call my-dir)
-
-PFW_CORE := external/parameter-framework
-PFW_DEFAULT_SCHEMAS_DIR := $(PFW_CORE)/upstream/schemas
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-TOOLS := frameworks/av/services/audiopolicy/engineconfigurable/tools
-BUILD_PFW_SETTINGS := $(TOOLS)/build_audio_pfw_settings.mk
-
-##################################################################
-# CONFIGURATION FILES
-##################################################################
-########## Policy PFW Structures #########
-######### Policy PFW Settings #########
-include $(CLEAR_VARS)
-LOCAL_MODULE := parameter-framework.policy
-LOCAL_MODULE_STEM := PolicyConfigurableDomains.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_MODULE_RELATIVE_PATH := parameter-framework/Settings/Policy
-LOCAL_REQUIRED_MODULES := libpolicy-subsystem
-
-PFW_EDD_FILES := \
- $(LOCAL_PATH)/../Settings/device_for_input_source.pfw \
- $(LOCAL_PATH)/../Settings/volumes.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_media.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_accessibility.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_dtmf.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_enforced_audible.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_phone.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_sonification.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_sonification_respectful.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_transmitted_through_speaker.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_rerouting.pfw \
- $(LOCAL_PATH)/Settings/device_for_product_strategy_patch.pfw
-PFW_CRITERION_TYPES_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criterion_types.xml
-PFW_CRITERIA_FILE := $(TARGET_OUT_VENDOR_ETC)/audio_policy_engine_criteria.xml
-PFW_TOPLEVEL_FILE := $(TARGET_OUT_VENDOR_ETC)/parameter-framework/ParameterFrameworkConfigurationPolicy.xml
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
-
-include $(BUILD_PFW_SETTINGS)
-
-endif #ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_configurable)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw
index a990879..9e0957c 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/Settings/device_for_input_source.pfw
@@ -18,7 +18,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/mic/applicable_input_device/mask
communication = 0
ambient = 0
@@ -36,7 +35,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_downlink/applicable_input_device/mask
communication = 0
ambient = 0
@@ -58,7 +56,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_call/applicable_input_device/mask
communication = 0
ambient = 0
@@ -80,7 +77,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_uplink/applicable_input_device/mask
communication = 0
ambient = 0
@@ -102,7 +98,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
communication = 0
ambient = 0
@@ -123,7 +118,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_recognition/applicable_input_device/mask
communication = 0
ambient = 0
@@ -142,7 +136,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/voice_communication/applicable_input_device/mask
communication = 0
ambient = 0
@@ -160,7 +153,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
communication = 0
ambient = 0
@@ -182,7 +174,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/hotword/applicable_input_device/mask
communication = 0
ambient = 0
@@ -201,7 +192,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/unprocessed/applicable_input_device/mask
communication = 0
ambient = 0
@@ -220,7 +210,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
communication = 0
ambient = 0
@@ -242,7 +231,6 @@
loopback = 0
ip = 0
bus = 0
- stub = 0
domain: DefaultAndMic
conf: A2dp
@@ -255,12 +243,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 1
wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
conf: Sco
AvailableInputDevices Includes BluetoothScoHeadset
@@ -273,12 +263,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 1
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 1
+ stub = 0
conf: WiredHeadset
AvailableInputDevices Includes WiredHeadset
@@ -290,12 +282,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 1
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
conf: UsbDevice
AvailableInputDevices Includes UsbDevice
@@ -307,12 +301,14 @@
usb_device = 1
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 1
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -324,12 +320,33 @@
usb_device = 0
builtin_mic = 1
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 0
builtin_mic = 1
bluetooth_sco_headset = 0
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources
+ component: default/applicable_input_device/mask/
+ bluetooth_a2dp = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ bluetooth_sco_headset = 0
+ stub = 1
+ component: mic/applicable_input_device/mask/
+ bluetooth_a2dp = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ bluetooth_sco_headset = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources
@@ -339,12 +356,14 @@
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
component: mic/applicable_input_device/mask/
bluetooth_a2dp = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
bluetooth_sco_headset = 0
+ stub = 0
domain: VoiceUplinkAndVoiceDownlinkAndVoiceCall
conf: VoiceCall
@@ -354,12 +373,29 @@
voice_downlink/applicable_input_device/mask/telephony_rx = 1
voice_call/applicable_input_device/mask/telephony_rx = 1
voice_uplink/applicable_input_device/mask/telephony_rx = 1
+ voice_downlink/applicable_input_device/mask/stub = 0
+ voice_call/applicable_input_device/mask/stub = 0
+ voice_uplink/applicable_input_device/mask/stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources
+ voice_downlink/applicable_input_device/mask/telephony_rx = 0
+ voice_call/applicable_input_device/mask/telephony_rx = 0
+ voice_uplink/applicable_input_device/mask/telephony_rx = 0
+ voice_downlink/applicable_input_device/mask/stub = 1
+ voice_call/applicable_input_device/mask/stub = 1
+ voice_uplink/applicable_input_device/mask/stub = 1
conf: Default
component: /Policy/policy/input_sources
voice_downlink/applicable_input_device/mask/telephony_rx = 0
voice_call/applicable_input_device/mask/telephony_rx = 0
voice_uplink/applicable_input_device/mask/telephony_rx = 0
+ voice_downlink/applicable_input_device/mask/stub = 0
+ voice_call/applicable_input_device/mask/stub = 0
+ voice_uplink/applicable_input_device/mask/stub = 0
domain: Camcorder
conf: BackMic
@@ -368,6 +404,7 @@
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
back_mic = 1
builtin_mic = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -375,11 +412,21 @@
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
back_mic = 0
builtin_mic = 1
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
+ back_mic = 0
+ builtin_mic = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources/camcorder/applicable_input_device/mask
back_mic = 0
builtin_mic = 0
+ stub = 0
domain: VoiceRecognitionAndUnprocessedAndHotword
conf: ScoHeadset
@@ -392,16 +439,19 @@
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 1
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 1
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
conf: WiredHeadset
AvailableInputDevices Includes WiredHeadset
@@ -411,17 +461,20 @@
bluetooth_sco_headset = 0
wired_headset = 1
usb_device = 0
+ stub = 0
builtin_mic = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 1
usb_device = 0
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 1
usb_device = 0
builtin_mic = 0
+ stub = 0
conf: UsbDevice
AvailableInputDevices Includes UsbDevice
@@ -432,16 +485,19 @@
wired_headset = 0
usb_device = 1
builtin_mic = 0
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 1
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 1
builtin_mic = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -452,17 +508,42 @@
wired_headset = 0
usb_device = 0
builtin_mic = 1
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 1
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 1
+ stub = 0
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources
+ component: voice_recognition/applicable_input_device/mask
+ bluetooth_sco_headset = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ stub = 1
+ component: unprocessed/applicable_input_device/mask
+ bluetooth_sco_headset = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ stub = 1
+ component: hotword/applicable_input_device/mask
+ bluetooth_sco_headset = 0
+ wired_headset = 0
+ usb_device = 0
+ builtin_mic = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources
component: voice_recognition/applicable_input_device/mask
@@ -470,16 +551,19 @@
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: unprocessed/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
component: hotword/applicable_input_device/mask
bluetooth_sco_headset = 0
wired_headset = 0
usb_device = 0
builtin_mic = 0
+ stub = 0
domain: VoiceCommunication
conf: ScoHeadset
@@ -495,6 +579,7 @@
usb_device = 0
builtin_mic = 0
back_mic = 0
+ stub = 0
conf: WiredHeadset
ForceUseForCommunication Is ForceNone
@@ -506,6 +591,7 @@
usb_device = 0
builtin_mic = 0
back_mic = 0
+ stub = 0
conf: UsbDevice
ForceUseForCommunication Is ForceNone
@@ -517,6 +603,7 @@
usb_device = 1
builtin_mic = 0
back_mic = 0
+ stub = 0
conf: BuiltinMic
AvailableInputDevices Includes BuiltinMic
@@ -532,6 +619,7 @@
usb_device = 0
builtin_mic = 1
back_mic = 0
+ stub = 0
conf: BackMic
ForceUseForCommunication Is ForceSpeaker
@@ -543,6 +631,7 @@
usb_device = 0
builtin_mic = 0
back_mic = 1
+ stub = 0
conf: Default
#
@@ -554,6 +643,7 @@
usb_device = 0
builtin_mic = 1
back_mic = 0
+ stub = 0
domain: RemoteSubmix
conf: RemoteSubmix
@@ -561,10 +651,19 @@
component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
remote_submix = 1
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
+ remote_submix = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources/remote_submix/applicable_input_device/mask
remote_submix = 0
+ stub = 0
domain: FmTuner
conf: FmTuner
@@ -572,8 +671,29 @@
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
fm_tuner = 1
+ stub = 0
+
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
+ fm_tuner = 0
+ stub = 1
conf: Default
component: /Policy/policy/input_sources/fm_tuner/applicable_input_device/mask
fm_tuner = 0
+ stub = 0
+
+ domain: Voice
+ conf: Stub
+ AvailableInputDevices Includes Default
+
+ /Policy/policy/input_sources/echo_reference/applicable_input_device/mask/stub = 1
+ /Policy/policy/input_sources/voice_performance/applicable_input_device/mask/stub = 1
+
+ conf: Default
+ /Policy/policy/input_sources/echo_reference/applicable_input_device/mask/stub = 0
+ /Policy/policy/input_sources/voice_performance/applicable_input_device/mask/stub = 0
+
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
new file mode 100644
index 0000000..ffd494e
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoInput/Android.bp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP No Input configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ "device_for_input_source.pfw",
+ ":volumes.pfw",
+ ],
+}
+prebuilt_etc {
+ name: "PolicySubsystem.xml",
+ vendor: true,
+ src: ":PolicySubsystem-no-strategy",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
new file mode 100644
index 0000000..6fca048
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/SettingsNoOutput/Android.bp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+// Import this namespace in order to use AOSP No output configuration example
+
+soong_namespace {
+ imports: [
+ "frameworks/av/services/audiopolicy/engineconfigurable/config/example/phone",
+ "frameworks/av/services/audiopolicy/config",
+ ],
+}
+
+prebuilt_etc {
+ name: "parameter-framework.policy",
+ filename_from_src: true,
+ vendor: true,
+ src: ":domaingeneratorpolicyrule_gen",
+ sub_dir: "parameter-framework/Settings/Policy",
+ required: [
+ "PolicyClass.xml",
+ "PolicySubsystem.xml",
+ "PolicySubsystem-CommonTypes.xml",
+ ],
+}
+genrule {
+ name: "domaingeneratorpolicyrule_gen",
+ defaults: ["domaingeneratorpolicyrule"],
+ srcs: [
+ ":audio_policy_pfw_toplevel",
+ ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criterion_types",
+ ":edd_files",
+ ],
+}
+filegroup {
+ name: "audio_policy_pfw_toplevel",
+ srcs: [":ParameterFrameworkConfigurationPolicy.userdebug.xml"],
+}
+filegroup {
+ name: "audio_policy_pfw_structure_files",
+ srcs: [
+ ":PolicyClass",
+ ":PolicySubsystem",
+ ":PolicySubsystem-CommonTypes",
+ ],
+}
+filegroup {
+ name: "edd_files",
+ srcs: [
+ "device_for_strategies.pfw",
+ ":volumes.pfw",
+ ":device_for_input_source.pfw",
+ ],
+}
+prebuilt_etc {
+ name: "PolicySubsystem.xml",
+ vendor: true,
+ src: ":PolicySubsystem-no-strategy",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
index b55ce2c..585ce87 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/examples/common/Structure/PolicySubsystem.xml
@@ -73,10 +73,13 @@
Mapping="Name:AUDIO_SOURCE_REMOTE_SUBMIX"/>
<Component Name="unprocessed" Type="InputSource"
Mapping="Name:AUDIO_SOURCE_UNPROCESSED"/>
+ <Component Name="voice_performance" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+ <Component Name="echo_reference" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_ECHO_REFERENCE"/>
<Component Name="fm_tuner" Type="InputSource" Mapping="Name:AUDIO_SOURCE_FM_TUNER"/>
<Component Name="hotword" Type="InputSource" Mapping="Name:AUDIO_SOURCE_HOTWORD"/>
</ComponentType>
-
<!--#################### INPUT SOURCE END ####################-->
</ComponentLibrary>
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index c37efca..3987294 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -33,6 +33,8 @@
#include <AudioIODescriptorInterface.h>
#include <ParameterManagerWrapper.h>
+#include <media/TypeConverter.h>
+
using std::string;
using std::map;
@@ -244,9 +246,9 @@
}
if (devices == AUDIO_DEVICE_NONE ||
(devices & availableOutputDevicesType) == AUDIO_DEVICE_NONE) {
- devices = getApmObserver()->getDefaultOutputDevice()->type();
- ALOGE_IF(devices == AUDIO_DEVICE_NONE, "%s: no valid default device defined", __FUNCTION__);
- return DeviceVector(getApmObserver()->getDefaultOutputDevice());
+ auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
+ ALOG_ASSERT(defaultDevice != nullptr, "no valid default device defined");
+ return DeviceVector(defaultDevice);
}
if (/*device_distinguishes_on_address(devices)*/ devices == AUDIO_DEVICE_OUT_BUS) {
// We do expect only one device for these types of devices
@@ -254,6 +256,14 @@
// If this criterion is not wished, need to ensure this device is available
const String8 address(productStrategies.getDeviceAddressForProductStrategy(ps).c_str());
ALOGV("%s:device 0x%x %s %d", __FUNCTION__, devices, address.c_str(), ps);
+ auto busDevice = availableOutputDevices.getDevice(devices, address, AUDIO_FORMAT_DEFAULT);
+ if (busDevice == nullptr) {
+ ALOGE("%s:unavailable device 0x%x %s, fallback on default", __func__, devices,
+ address.c_str());
+ auto defaultDevice = getApmObserver()->getDefaultOutputDevice();
+ ALOG_ASSERT(defaultDevice != nullptr, "Default Output Device NOT available");
+ return DeviceVector(defaultDevice);
+ }
return DeviceVector(availableOutputDevices.getDevice(devices,
address,
AUDIO_FORMAT_DEFAULT));
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index 8c16972..d9e97af 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -16,14 +16,17 @@
name: "tools_default",
version: {
py2: {
- enabled: true,
+ enabled: false,
},
py3: {
- enabled: false,
+ enabled: true,
},
},
}
+//##################################################################################################
+// Tools for audio policy engine criterion type configuration file
+//
python_binary_host {
name: "buildPolicyCriterionTypes.py",
main: "buildPolicyCriterionTypes.py",
@@ -33,6 +36,30 @@
defaults: ["tools_default"],
}
+genrule_defaults {
+ name: "buildpolicycriteriontypesrule",
+ tools: ["buildPolicyCriterionTypes.py"],
+ cmd: "cp $(locations :audio_policy_configuration_files) $(genDir)/. && " +
+ "cp $(location :audio_policy_configuration_top_file) $(genDir)/audio_policy_configuration.xml && " +
+ "$(location buildPolicyCriterionTypes.py) " +
+ // @todo update if 1428659 is merged "--androidaudiobaseheader $(location :android_audio_base_header_file) " +
+ " --androidaudiobaseheader system/media/audio/include/system/audio-base.h " +
+ "--audiopolicyconfigurationfile $(genDir)/audio_policy_configuration.xml " +
+ "--criteriontypes $(location :audio_policy_engine_criterion_types_template) " +
+ "--outputfile $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // @todo uncomment if 1428659 is merged":android_audio_base_header_file",
+ ":audio_policy_engine_criterion_types_template",
+ // ":audio_policy_configuration_top_file",
+ // ":audio_policy_configuration_files",
+ ],
+ out: ["audio_policy_engine_criterion_types.xml"],
+}
+
+//##################################################################################################
+// Tools for audio policy engine parameter framework configurable domains
+//
python_binary_host {
name: "domainGeneratorPolicy.py",
main: "domainGeneratorPolicy.py",
@@ -50,6 +77,38 @@
],
}
+genrule_defaults {
+ name: "domaingeneratorpolicyrule",
+ tools: [
+ "domainGeneratorPolicy.py",
+ "domainGeneratorConnector",
+ ],
+ cmd: "mkdir -p $(genDir)/Structure/Policy && " +
+ "cp $(locations :audio_policy_pfw_structure_files) $(genDir)/Structure/Policy && " +
+ "cp $(location :audio_policy_pfw_toplevel) $(genDir)/top_level && " +
+ "$(location domainGeneratorPolicy.py) " +
+ "--validate " +
+ "--domain-generator-tool $(location domainGeneratorConnector) " +
+ "--toplevel-config $(genDir)/top_level " +
+ "--criteria $(location :audio_policy_engine_criteria) " +
+ "--criteriontypes $(location :audio_policy_engine_criterion_types) " +
+ "--add-edds $(locations :edd_files) " +
+ "--schemas-dir external/parameter-framework/upstream/schemas " +
+ " > $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // ":audio_policy_pfw_toplevel",
+ // ":audio_policy_pfw_structure_files",
+ ":audio_policy_engine_criteria",
+ // ":audio_policy_engine_criterion_types",
+ // ":edd_files",
+ ],
+ out: ["PolicyConfigurableDomains.xml"],
+}
+
+//##################################################################################################
+// Tools for policy parameter-framework product strategies structure file generation
+//
python_binary_host {
name: "buildStrategiesStructureFile.py",
main: "buildStrategiesStructureFile.py",
@@ -58,3 +117,19 @@
],
defaults: ["tools_default"],
}
+
+genrule_defaults {
+ name: "buildstrategiesstructurerule",
+ tools: ["buildStrategiesStructureFile.py"],
+ cmd: "cp $(locations :audio_policy_engine_configuration_files) $(genDir) && ls -l $(genDir) &&"+
+ "$(location buildStrategiesStructureFile.py) " +
+ "--audiopolicyengineconfigurationfile $(genDir)/audio_policy_engine_configuration.xml "+
+ "--productstrategiesstructurefile $(location :product_strategies_structure_template) " +
+ "--outputfile $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // ":audio_policy_engine_configuration_files",
+ ":product_strategies_structure_template",
+ ],
+ out: ["ProductStrategies.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
index a63c858..b8b60c1 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildPolicyCriterionTypes.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
#
# Copyright 2018, The Android Open Source Project
@@ -19,10 +19,8 @@
import argparse
import re
import sys
-import tempfile
import os
import logging
-import subprocess
import xml.etree.ElementTree as ET
import xml.etree.ElementInclude as EI
import xml.dom.minidom as MINIDOM
@@ -49,33 +47,35 @@
def parseArgs():
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
- audio criterion type file generator.\n\
- Exit with the number of (recoverable or not) error that occured.")
+ audio criterion type file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occured.")
argparser.add_argument('--androidaudiobaseheader',
- help="Android Audio Base C header file, Mandatory.",
- metavar="ANDROID_AUDIO_BASE_HEADER",
- type=argparse.FileType('r'),
- required=True)
+ help="Android Audio Base C header file, Mandatory.",
+ metavar="ANDROID_AUDIO_BASE_HEADER",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--audiopolicyconfigurationfile',
- help="Android Audio Policy Configuration file, Mandatory.",
- metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
- type=argparse.FileType('r'),
- required=True)
+ help="Android Audio Policy Configuration file, Mandatory.",
+ metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--criteriontypes',
- help="Criterion types XML base file, in \
- '<criterion_types> \
- <criterion_type name="" type=<inclusive|exclusive> values=<value1,value2,...>/>' \
- format. Mandatory.",
- metavar="CRITERION_TYPE_FILE",
- type=argparse.FileType('r'),
- required=True)
+ help="Criterion types XML base file, in \
+ '<criterion_types> \
+ <criterion_type name="" type=<inclusive|exclusive> \
+ values=<value1,value2,...>/>' \
+ format. Mandatory.",
+ metavar="CRITERION_TYPE_FILE",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--outputfile',
- help="Criterion types outputfile file. Mandatory.",
- metavar="CRITERION_TYPE_OUTPUT_FILE",
- type=argparse.FileType('w'),
- required=True)
+ help="Criterion types outputfile file. Mandatory.",
+ metavar="CRITERION_TYPE_OUTPUT_FILE",
+ type=argparse.FileType('w'),
+ required=True)
argparser.add_argument('--verbose',
- action='store_true')
+ action='store_true')
return argparser.parse_args()
@@ -120,7 +120,7 @@
reparsed = MINIDOM.parseString(xmlstr)
prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
- outputFile.write(prettyXmlStr.encode('utf-8'))
+ outputFile.write(prettyXmlStr)
def capitalizeLine(line):
return ' '.join((w.capitalize() for w in line.split(' ')))
@@ -137,30 +137,30 @@
#
address_criteria_mapping_table = {
'sink' : "OutputDevicesAddressesType",
- 'source' : "InputDevicesAddressesType" }
+ 'source' : "InputDevicesAddressesType"}
address_criteria = {
'OutputDevicesAddressesType' : [],
- 'InputDevicesAddressesType' : [] }
+ 'InputDevicesAddressesType' : []}
- oldWorkingDir = os.getcwd()
- print "Current working directory %s" % oldWorkingDir
+ old_working_dir = os.getcwd()
+ print("Current working directory %s" % old_working_dir)
- newDir = os.path.join(oldWorkingDir , audiopolicyconfigurationfile.name)
+ new_dir = os.path.join(old_working_dir, audiopolicyconfigurationfile.name)
policy_in_tree = ET.parse(audiopolicyconfigurationfile)
- os.chdir(os.path.dirname(os.path.normpath(newDir)))
+ os.chdir(os.path.dirname(os.path.normpath(new_dir)))
- print "new working directory %s" % os.getcwd()
+ print("new working directory %s" % os.getcwd())
policy_root = policy_in_tree.getroot()
EI.include(policy_root)
- os.chdir(oldWorkingDir)
+ os.chdir(old_working_dir)
for device in policy_root.iter('devicePort'):
for key in address_criteria_mapping_table.keys():
- if device.get('role') == key and device.get('address') :
+ if device.get('role') == key and device.get('address'):
logging.info("{}: <{}>".format(key, device.get('address')))
address_criteria[address_criteria_mapping_table[key]].append(device.get('address'))
@@ -188,15 +188,15 @@
all_criteria = {
'AndroidModeType' : {},
'OutputDevicesMaskType' : {},
- 'InputDevicesMaskType' : {} }
+ 'InputDevicesMaskType' : {}}
#
# _CNT, _MAX, _ALL and _NONE are prohibited values as ther are just helpers for enum users.
#
- ignored_values = [ 'CNT', 'MAX', 'ALL', 'NONE' ]
+ ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
criteria_pattern = re.compile(
- r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))\_" \
+ r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
r"(?P<values>(?:0[xX])?[0-9a-fA-F]+)")
@@ -221,7 +221,7 @@
logging.info("criterion {} duplicated values:".format(criterion_name))
logging.info("{}:{}".format(numerical_value, literal))
logging.info("KEEPING LATEST")
- for key in all_criteria[criterion_name].keys():
+ for key in list(all_criteria[criterion_name]):
if all_criteria[criterion_name][key] == int(numerical_value, 0):
del all_criteria[criterion_name][key]
diff --git a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
index af40602..f69d346 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
#
# Copyright 2019, The Android Open Source Project
@@ -17,16 +17,12 @@
#
import argparse
-import re
import sys
-import tempfile
import os
import logging
-import subprocess
import xml.etree.ElementTree as ET
import xml.etree.ElementInclude as EI
import xml.dom.minidom as MINIDOM
-from collections import OrderedDict
#
# Helper script that helps to feed at build time the XML Product Strategies Structure file file used
@@ -46,33 +42,34 @@
def parseArgs():
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
- product strategies structure file generator.\n\
- Exit with the number of (recoverable or not) error that occured.")
+ product strategies structure file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occured.")
argparser.add_argument('--audiopolicyengineconfigurationfile',
- help="Android Audio Policy Engine Configuration file, Mandatory.",
- metavar="(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)",
- type=argparse.FileType('r'),
- required=True)
+ help="Android Audio Policy Engine Configuration file, Mandatory.",
+ metavar="(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--productstrategiesstructurefile',
- help="Product Strategies Structure XML base file, Mandatory.",
- metavar="STRATEGIES_STRUCTURE_FILE",
- type=argparse.FileType('r'),
- required=True)
+ help="Product Strategies Structure XML base file, Mandatory.",
+ metavar="STRATEGIES_STRUCTURE_FILE",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--outputfile',
- help="Product Strategies Structure output file, Mandatory.",
- metavar="STRATEGIES_STRUCTURE_OUTPUT_FILE",
- type=argparse.FileType('w'),
- required=True)
+ help="Product Strategies Structure output file, Mandatory.",
+ metavar="STRATEGIES_STRUCTURE_OUTPUT_FILE",
+ type=argparse.FileType('w'),
+ required=True)
argparser.add_argument('--verbose',
- action='store_true')
+ action='store_true')
return argparser.parse_args()
-def generateXmlStructureFile(strategies, strategyStructureInFile, outputFile):
+def generateXmlStructureFile(strategies, strategy_structure_in_file, output_file):
- logging.info("Importing strategyStructureInFile {}".format(strategyStructureInFile))
- strategies_in_tree = ET.parse(strategyStructureInFile)
+ logging.info("Importing strategy_structure_in_file {}".format(strategy_structure_in_file))
+ strategies_in_tree = ET.parse(strategy_structure_in_file)
strategies_root = strategies_in_tree.getroot()
strategy_components = strategies_root.find('ComponentType')
@@ -80,13 +77,15 @@
for strategy_name in strategies:
context_mapping = "".join(map(str, ["Name:", strategy_name]))
strategy_pfw_name = strategy_name.replace('STRATEGY_', '').lower()
- strategy_component_node = ET.SubElement(strategy_components, "Component", Name=strategy_pfw_name, Type="ProductStrategy", Mapping=context_mapping)
+ ET.SubElement(strategy_components, "Component",
+ Name=strategy_pfw_name, Type="ProductStrategy",
+ Mapping=context_mapping)
xmlstr = ET.tostring(strategies_root, encoding='utf8', method='xml')
reparsed = MINIDOM.parseString(xmlstr)
prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
- outputFile.write(prettyXmlStr.encode('utf-8'))
+ output_file.write(prettyXmlStr)
def capitalizeLine(line):
return ' '.join((w.capitalize() for w in line.split(' ')))
@@ -97,26 +96,27 @@
#
def parseAndroidAudioPolicyEngineConfigurationFile(audiopolicyengineconfigurationfile):
- logging.info("Checking Audio Policy Engine Configuration file {}".format(audiopolicyengineconfigurationfile))
+ logging.info("Checking Audio Policy Engine Configuration file {}".format(
+ audiopolicyengineconfigurationfile))
#
# extract all product strategies name from audio policy engine configuration file
#
strategy_names = []
- oldWorkingDir = os.getcwd()
- print "Current working directory %s" % oldWorkingDir
+ old_working_dir = os.getcwd()
+ print("Current working directory %s" % old_working_dir)
- newDir = os.path.join(oldWorkingDir , audiopolicyengineconfigurationfile.name)
+ new_dir = os.path.join(old_working_dir, audiopolicyengineconfigurationfile.name)
policy_engine_in_tree = ET.parse(audiopolicyengineconfigurationfile)
- os.chdir(os.path.dirname(os.path.normpath(newDir)))
+ os.chdir(os.path.dirname(os.path.normpath(new_dir)))
- print "new working directory %s" % os.getcwd()
+ print("new working directory %s" % os.getcwd())
policy_engine_root = policy_engine_in_tree.getroot()
EI.include(policy_engine_root)
- os.chdir(oldWorkingDir)
+ os.chdir(old_working_dir)
for strategy in policy_engine_root.iter('ProductStrategy'):
strategy_names.append(strategy.get('name'))
@@ -128,7 +128,8 @@
logging.root.setLevel(logging.INFO)
args = parseArgs()
- strategies = parseAndroidAudioPolicyEngineConfigurationFile(args.audiopolicyengineconfigurationfile)
+ strategies = parseAndroidAudioPolicyEngineConfigurationFile(
+ args.audiopolicyengineconfigurationfile)
product_strategies_structure = args.productstrategiesstructurefile
diff --git a/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk b/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
deleted file mode 100644
index ac60ef7..0000000
--- a/services/audiopolicy/engineconfigurable/tools/build_audio_pfw_settings.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(HOST_OUT_EXECUTABLES)/domainGeneratorPolicy.py \
- $(PFW_TOPLEVEL_FILE) $(PFW_CRITERIA_FILE) $(PFW_CRITERION_TYPES_FILE)
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): MY_TOOL := $(HOST_OUT_EXECUTABLES)/domainGeneratorPolicy.py
-$(LOCAL_BUILT_MODULE): MY_TOPLEVEL_FILE := $(PFW_TOPLEVEL_FILE)
-$(LOCAL_BUILT_MODULE): MY_CRITERIA_FILE := $(PFW_CRITERIA_FILE)
-$(LOCAL_BUILT_MODULE): MY_TUNING_FILE := $(PFW_TUNING_FILE)
-$(LOCAL_BUILT_MODULE): MY_EDD_FILES := $(PFW_EDD_FILES)
-$(LOCAL_BUILT_MODULE): MY_DOMAIN_FILES := $(PFW_DOMAIN_FILES)
-$(LOCAL_BUILT_MODULE): MY_SCHEMAS_DIR := $(PFW_SCHEMAS_DIR)
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(PFW_CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
-
- "$(MY_TOOL)" --validate \
- --toplevel-config "$(MY_TOPLEVEL_FILE)" \
- --criteria "$(MY_CRITERIA_FILE)" \
- --criteriontypes "$(MY_CRITERION_TYPES_FILE)" \
- --initial-settings $(MY_TUNING_FILE) \
- --add-edds $(MY_EDD_FILES) \
- --add-domains $(MY_DOMAIN_FILES) \
- --schemas-dir $(MY_SCHEMAS_DIR) > "$@"
-
-
-# Clear variables for further use
-PFW_TOPLEVEL_FILE :=
-PFW_STRUCTURE_FILES :=
-PFW_CRITERIA_FILE :=
-PFW_CRITERION_TYPES_FILE :=
-PFW_TUNING_FILE :=
-PFW_EDD_FILES :=
-PFW_DOMAIN_FILES :=
-PFW_SCHEMAS_DIR := $(PFW_DEFAULT_SCHEMAS_DIR)
diff --git a/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
index 4dec9a2..b0c4b66 100755
--- a/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
+++ b/services/audiopolicy/engineconfigurable/tools/domainGeneratorPolicy.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/python3
#
# Copyright 2018, The Android Open Source Project
@@ -16,12 +16,7 @@
# limitations under the License.
#
-import EddParser
-from PFWScriptGenerator import PfwScriptTranslator
-import hostConfig
-
import argparse
-import re
import sys
import tempfile
import os
@@ -29,6 +24,10 @@
import subprocess
import xml.etree.ElementTree as ET
+import EddParser
+from PFWScriptGenerator import PfwScriptTranslator
+import hostConfig
+
#
# In order to build the XML Settings file at build time, an instance of the parameter-framework
# shall be started and fed with all the criterion types/criteria that will be used by
@@ -39,61 +38,67 @@
def parseArgs():
argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
- Settings file generator.\n\
- Exit with the number of (recoverable or not) error that occured.")
+ Settings file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occured.")
+ argparser.add_argument('--domain-generator-tool',
+ help="ParameterFramework domain generator tool. Mandatory.",
+ metavar="PFW_DOMAIN_GENERATOR_TOOL",
+ required=True)
argparser.add_argument('--toplevel-config',
- help="Top-level parameter-framework configuration file. Mandatory.",
- metavar="TOPLEVEL_CONFIG_FILE",
- required=True)
+ help="Top-level parameter-framework configuration file. Mandatory.",
+ metavar="TOPLEVEL_CONFIG_FILE",
+ required=True)
argparser.add_argument('--criteria',
- help="Criteria file, in XML format: \
- in '<criteria> \
- <criterion name="" type=""/> \
- </criteria>' \
- format. Mandatory.",
- metavar="CRITERIA_FILE",
- type=argparse.FileType('r'),
- required=True)
+ help="Criteria file, in XML format: \
+ in '<criteria> \
+ <criterion name="" type=""/> \
+ </criteria>' \
+ format. Mandatory.",
+ metavar="CRITERIA_FILE",
+ type=argparse.FileType('r'),
+ required=True)
argparser.add_argument('--criteriontypes',
- help="Criterion types XML file, in \
- '<criterion_types> \
- <criterion_type name="" type=<inclusive|exclusive> values=<value1,value2,...>/> \
- </criterion_types>' \
- format. Mandatory.",
- metavar="CRITERION_TYPE_FILE",
- type=argparse.FileType('r'),
- required=False)
+ help="Criterion types XML file, in \
+ '<criterion_types> \
+ <criterion_type name="" type=<inclusive|exclusive> \
+ values=<value1,value2,...>/> \
+ </criterion_types>' \
+ format. Mandatory.",
+ metavar="CRITERION_TYPE_FILE",
+ type=argparse.FileType('r'),
+ required=False)
argparser.add_argument('--initial-settings',
- help="Initial XML settings file (containing a \
- <ConfigurableDomains> tag",
- nargs='?',
- default=None,
- metavar="XML_SETTINGS_FILE")
+ help="Initial XML settings file (containing a \
+ <ConfigurableDomains> tag",
+ nargs='?',
+ default=None,
+ metavar="XML_SETTINGS_FILE")
argparser.add_argument('--add-domains',
- help="List of single domain files (each containing a single \
- <ConfigurableDomain> tag",
- metavar="XML_DOMAIN_FILE",
- nargs='*',
- dest='xml_domain_files',
- default=[])
+ help="List of single domain files (each containing a single \
+ <ConfigurableDomain> tag",
+ metavar="XML_DOMAIN_FILE",
+ nargs='*',
+ dest='xml_domain_files',
+ default=[])
argparser.add_argument('--add-edds',
- help="List of files in EDD syntax (aka \".pfw\" files)",
- metavar="EDD_FILE",
- type=argparse.FileType('r'),
- nargs='*',
- default=[],
- dest='edd_files')
+ help="List of files in EDD syntax (aka \".pfw\" files)",
+ metavar="EDD_FILE",
+ type=argparse.FileType('r'),
+ nargs='*',
+ default=[],
+ dest='edd_files')
argparser.add_argument('--schemas-dir',
- help="Directory of parameter-framework XML Schemas for generation \
- validation",
- default=None)
+ help="Directory of parameter-framework XML Schemas for generation \
+ validation",
+ default=None)
argparser.add_argument('--target-schemas-dir',
- help="Ignored. Kept for retro-compatibility")
+ help="Ignored. Kept for retro-compatibility")
argparser.add_argument('--validate',
- help="Validate the settings against XML schemas",
- action='store_true')
+ help="Validate the settings against XML schemas",
+ action='store_true')
argparser.add_argument('--verbose',
- action='store_true')
+ action='store_true')
return argparser.parse_args()
@@ -112,7 +117,6 @@
logging.info("Importing criterionTypesFile {}".format(criterionTypesFile))
criteria_root = criteria_tree.getroot()
- criterion_types_root = criterion_types_tree.getroot()
all_criteria = []
for criterion in criteria_root.findall('criterion'):
@@ -165,7 +169,7 @@
try:
root.propagate()
- except EddParser.MyPropagationError, ex :
+ except EddParser.MyPropagationError as ex:
logging.critical(str(ex))
logging.info("EXIT ON FAILURE")
exit(1)
@@ -179,32 +183,32 @@
# It takes as input the collection of criteria, the domains and the simplified settings read from
# pfw.
#
-def generateDomainCommands(logging, all_criteria, initial_settings, xml_domain_files, parsed_edds):
- # create and inject all the criteria
- logging.info("Creating all criteria")
- for criterion in all_criteria:
- yield ["createSelectionCriterion", criterion['inclusive'],
- criterion['name']] + criterion['values']
+def generateDomainCommands(logger, all_criteria, initial_settings, xml_domain_files, parsed_edds):
+ # create and inject all the criteria
+ logger.info("Creating all criteria")
+ for criterion in all_criteria:
+ yield ["createSelectionCriterion", criterion['inclusive'],
+ criterion['name']] + criterion['values']
- yield ["start"]
+ yield ["start"]
- # Import initial settings file
- if initial_settings:
- logging.info("Importing initial settings file {}".format(initial_settings))
- yield ["importDomainsWithSettingsXML", initial_settings]
+ # Import initial settings file
+ if initial_settings:
+ logger.info("Importing initial settings file {}".format(initial_settings))
+ yield ["importDomainsWithSettingsXML", initial_settings]
- # Import each standalone domain files
- for domain_file in xml_domain_files:
- logging.info("Importing single domain file {}".format(domain_file))
- yield ["importDomainWithSettingsXML", domain_file]
+ # Import each standalone domain files
+ for domain_file in xml_domain_files:
+ logger.info("Importing single domain file {}".format(domain_file))
+ yield ["importDomainWithSettingsXML", domain_file]
- # Generate the script for each EDD file
- for filename, parsed_edd in parsed_edds:
- logging.info("Translating and injecting EDD file {}".format(filename))
- translator = PfwScriptTranslator()
- parsed_edd.translate(translator)
- for command in translator.getScript():
- yield command
+ # Generate the script for each EDD file
+ for filename, parsed_edd in parsed_edds:
+ logger.info("Translating and injecting EDD file {}".format(filename))
+ translator = PfwScriptTranslator()
+ parsed_edd.translate(translator)
+ for command in translator.getScript():
+ yield command
#
# Entry point of the domain generator.
@@ -232,30 +236,29 @@
prefix="TMPdomainGeneratorPFConfig_")
install_path = os.path.dirname(os.path.realpath(args.toplevel_config))
- hostConfig.configure(
- infile=args.toplevel_config,
- outfile=fake_toplevel_config,
- structPath=install_path)
+ hostConfig.configure(infile=args.toplevel_config,
+ outfile=fake_toplevel_config,
+ structPath=install_path)
fake_toplevel_config.close()
# Create the connector. Pipe its input to us in order to write commands;
# connect its output to stdout in order to have it dump the domains
# there; connect its error output to stderr.
- connector = subprocess.Popen(["domainGeneratorConnector",
- fake_toplevel_config.name,
- 'verbose' if args.verbose else 'no-verbose',
- 'validate' if args.validate else 'no-validate',
- args.schemas_dir],
- stdout=sys.stdout, stdin=subprocess.PIPE, stderr=sys.stderr)
+ connector = subprocess.Popen([args.domain_generator_tool,
+ fake_toplevel_config.name,
+ 'verbose' if args.verbose else 'no-verbose',
+ 'validate' if args.validate else 'no-validate',
+ args.schemas_dir],
+ stdout=sys.stdout, stdin=subprocess.PIPE, stderr=sys.stderr)
initial_settings = None
if args.initial_settings:
initial_settings = os.path.realpath(args.initial_settings)
for command in generateDomainCommands(logging, all_criteria, initial_settings,
- args.xml_domain_files, parsed_edds):
- connector.stdin.write('\0'.join(command))
- connector.stdin.write("\n")
+ args.xml_domain_files, parsed_edds):
+ connector.stdin.write('\0'.join(command).encode('utf-8'))
+ connector.stdin.write("\n".encode('utf-8'))
# Closing the connector's input triggers the domain generation
connector.stdin.close()
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk b/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
deleted file mode 100644
index dab5a0f..0000000
--- a/services/audiopolicy/engineconfigurable/tools/provision_criterion_types_from_android_headers.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(HOST_OUT_EXECUTABLES)/buildPolicyCriterionTypes.py \
- $(CRITERION_TYPES_FILE) $(AUDIO_POLICY_CONFIGURATION_FILE) \
- $(ANDROID_AUDIO_BASE_HEADER_FILE)
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TYPES_FILE := $(CRITERION_TYPES_FILE)
-$(LOCAL_BUILT_MODULE): MY_ANDROID_AUDIO_BASE_HEADER_FILE := $(ANDROID_AUDIO_BASE_HEADER_FILE)
-$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_CONFIGURATION_FILE := $(AUDIO_POLICY_CONFIGURATION_FILE)
-$(LOCAL_BUILT_MODULE): MY_CRITERION_TOOL := $(HOST_OUT_EXECUTABLES)/buildPolicyCriterionTypes.py
-$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
-
- "$(MY_CRITERION_TOOL)" \
- --androidaudiobaseheader "$(MY_ANDROID_AUDIO_BASE_HEADER_FILE)" \
- --audiopolicyconfigurationfile "$(MY_AUDIO_POLICY_CONFIGURATION_FILE)" \
- --criteriontypes "$(MY_CRITERION_TYPES_FILE)" \
- --outputfile "$(@)"
-
-# Clear variables for further use
-CRITERION_TYPES_FILE :=
-ANDROID_AUDIO_BASE_HEADER_FILE :=
-AUDIO_POLICY_CONFIGURATION_FILE :=
diff --git a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk b/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
deleted file mode 100644
index f2b1a19..0000000
--- a/services/audiopolicy/engineconfigurable/tools/provision_strategies_structure.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_ADDITIONAL_DEPENDENCIES += \
- $(HOST_OUT_EXECUTABLES)/buildStrategiesStructureFile.py \
- $(STRATEGIES_STRUCTURE_FILE) $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
-
-include $(BUILD_SYSTEM)/base_rules.mk
-
-$(LOCAL_BUILT_MODULE): MY_STRATEGIES_STRUCTURE_FILE := $(STRATEGIES_STRUCTURE_FILE)
-$(LOCAL_BUILT_MODULE): MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE := $(AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)
-$(LOCAL_BUILT_MODULE): MY_PROVISION_TOOL := $(HOST_OUT_EXECUTABLES)/buildStrategiesStructureFile.py
-$(LOCAL_BUILT_MODULE): $(LOCAL_ADDITIONAL_DEPENDENCIES)
-
- "$(MY_PROVISION_TOOL)" \
- --audiopolicyengineconfigurationfile "$(MY_AUDIO_POLICY_ENGINE_CONFIGURATION_FILE)" \
- --productstrategiesstructurefile "$(MY_STRATEGIES_STRUCTURE_FILE)" \
- --outputfile "$(@)"
-
-# Clear variables for further use
-STRATEGIES_STRUCTURE_FILE :=
-AUDIO_POLICY_ENGINE_CONFIGURATION_FILE :=
diff --git a/services/audiopolicy/enginedefault/config/example/Android.bp b/services/audiopolicy/enginedefault/config/example/Android.bp
new file mode 100644
index 0000000..0bfcaa1
--- /dev/null
+++ b/services/audiopolicy/enginedefault/config/example/Android.bp
@@ -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.
+ */
+
+// Import this namespace in order to use AOSP Phone with Default Engine configuration example
+
+soong_namespace {
+}
+
+prebuilt_etc {
+ name: "audio_policy_engine_configuration.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_configuration.xml",
+ required: [
+ ":audio_policy_engine_stream_volumes.xml",
+ ":audio_policy_engine_default_stream_volumes.xml",
+ ":audio_policy_engine_product_strategies.xml",
+ ],
+}
+prebuilt_etc {
+ name: "audio_policy_engine_product_strategies.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_product_strategies.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_stream_volumes.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_stream_volumes.xml",
+}
+prebuilt_etc {
+ name: "audio_policy_engine_default_stream_volumes.xml",
+ vendor: true,
+ src: "phone/audio_policy_engine_default_stream_volumes.xml",
+}
diff --git a/services/audiopolicy/enginedefault/config/example/Android.mk b/services/audiopolicy/enginedefault/config/example/Android.mk
deleted file mode 100644
index 0badac8..0000000
--- a/services/audiopolicy/enginedefault/config/example/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-##################################################################
-# CONFIGURATION TOP FILE
-##################################################################
-
-ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_default)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_configuration.xml
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-
-LOCAL_REQUIRED_MODULES := \
- audio_policy_engine_product_strategies.xml \
- audio_policy_engine_stream_volumes.xml \
- audio_policy_engine_default_stream_volumes.xml
-
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_product_strategies.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := audio_policy_engine_default_stream_volumes.xml
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := ETC
-LOCAL_VENDOR_MODULE := true
-LOCAL_SRC_FILES := phone/$(LOCAL_MODULE)
-include $(BUILD_PREBUILT)
-
-endif # ifeq ($(BUILD_AUDIO_POLICY_EXAMPLE_CONFIGURATION), phone_default)
diff --git a/services/audiopolicy/manager/AudioPolicyFactory.cpp b/services/audiopolicy/manager/AudioPolicyFactory.cpp
index 7aff6a9..476a1ec 100644
--- a/services/audiopolicy/manager/AudioPolicyFactory.cpp
+++ b/services/audiopolicy/manager/AudioPolicyFactory.cpp
@@ -21,7 +21,13 @@
extern "C" AudioPolicyInterface* createAudioPolicyManager(
AudioPolicyClientInterface *clientInterface)
{
- return new AudioPolicyManager(clientInterface);
+ AudioPolicyManager *apm = new AudioPolicyManager(clientInterface);
+ status_t status = apm->initialize();
+ if (status != NO_ERROR) {
+ delete apm;
+ apm = nullptr;
+ }
+ return apm;
}
extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0694584..83ae35e 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4306,7 +4306,6 @@
: AudioPolicyManager(clientInterface, false /*forTesting*/)
{
loadConfig();
- initialize();
}
void AudioPolicyManager::loadConfig() {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index d88d1ec..5f651cc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -307,6 +307,8 @@
return volumeGroup != VOLUME_GROUP_NONE ? NO_ERROR : BAD_VALUE;
}
+ status_t initialize();
+
protected:
// A constructor that allows more fine-grained control over initialization process,
// used in automatic tests.
@@ -321,7 +323,6 @@
// - initialize.
AudioPolicyConfig& getConfig() { return mConfig; }
void loadConfig();
- status_t initialize();
// From AudioPolicyManagerObserver
virtual const AudioPatchCollection &getAudioPatches() const
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 62010e1..90939ce 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -409,12 +409,17 @@
// Another client in the same UID has already been allowed to capture
// OR The client is the assistant
// AND an accessibility service is on TOP or a RTT call is active
-// AND the source is VOICE_RECOGNITION or HOTWORD
-// OR uses VOICE_RECOGNITION AND is on TOP
-// OR uses HOTWORD
+// AND the source is VOICE_RECOGNITION or HOTWORD
+// OR uses VOICE_RECOGNITION AND is on TOP
+// OR uses HOTWORD
// AND there is no active privacy sensitive capture or call
// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
// OR The client is an accessibility service
+// AND Is on TOP
+// AND the source is VOICE_RECOGNITION or HOTWORD
+// OR The assistant is not on TOP
+// AND there is no active privacy sensitive capture or call
+// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
// AND is on TOP
// AND the source is VOICE_RECOGNITION or HOTWORD
// OR the client source is virtual (remote submix, call audio TX or RX...)
@@ -422,7 +427,7 @@
// AND The assistant is not on TOP
// AND is on TOP or latest started
// AND there is no active privacy sensitive capture or call
-// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+// OR client has CAPTURE_AUDIO_OUTPUT privileged permission
sp<AudioRecordClient> topActive;
sp<AudioRecordClient> latestActive;
@@ -459,7 +464,8 @@
}
bool isAssistant = mUidPolicy->isAssistantUid(current->uid);
- if (appState == APP_STATE_TOP) {
+ bool isAccessibility = mUidPolicy->isA11yUid(current->uid);
+ if (appState == APP_STATE_TOP && !isAccessibility) {
if (current->startTimeNs > topStartNs) {
topActive = current;
topStartNs = current->startTimeNs;
@@ -468,10 +474,13 @@
isAssistantOnTop = true;
}
}
- // Assistant capturing for HOTWORD not considered for latest active to avoid
- // masking regular clients started before
- if (current->startTimeNs > latestStartNs &&
- !(current->attributes.source == AUDIO_SOURCE_HOTWORD && isAssistant)) {
+ // Assistant capturing for HOTWORD or Accessibility services not considered
+ // for latest active to avoid masking regular clients started before
+ if (current->startTimeNs > latestStartNs
+ && !((current->attributes.source == AUDIO_SOURCE_HOTWORD
+ || isA11yOnTop || rttCallActive)
+ && isAssistant)
+ && !isAccessibility) {
latestActive = current;
latestStartNs = current->startTimeNs;
}
@@ -544,10 +553,20 @@
} else if (mUidPolicy->isA11yUid(current->uid)) {
// For accessibility service allow capture if:
// Is on TOP
- // AND the source is VOICE_RECOGNITION or HOTWORD
- if (isA11yOnTop &&
- (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD)) {
- allowCapture = true;
+ // AND the source is VOICE_RECOGNITION or HOTWORD
+ // Or
+ // The assistant is not on TOP
+ // AND there is no active privacy sensitive capture or call
+ // OR client has CAPTURE_AUDIO_OUTPUT privileged permission
+ if (isA11yOnTop) {
+ if (source == AUDIO_SOURCE_VOICE_RECOGNITION || source == AUDIO_SOURCE_HOTWORD) {
+ allowCapture = true;
+ }
+ } else {
+ if (!isAssistantOnTop
+ && (!(isSensitiveActive || isInCall) || current->canCaptureOutput)) {
+ allowCapture = true;
+ }
}
}
setAppState_l(current->uid,
@@ -706,11 +725,11 @@
if (in == BAD_TYPE || out == BAD_TYPE || err == BAD_TYPE) {
return BAD_VALUE;
}
- if (args.size() == 3 && args[0] == String16("set-uid-state")) {
+ if (args.size() >= 3 && args[0] == String16("set-uid-state")) {
return handleSetUidState(args, err);
- } else if (args.size() == 2 && args[0] == String16("reset-uid-state")) {
+ } else if (args.size() >= 2 && args[0] == String16("reset-uid-state")) {
return handleResetUidState(args, err);
- } else if (args.size() == 2 && args[0] == String16("get-uid-state")) {
+ } else if (args.size() >= 2 && args[0] == String16("get-uid-state")) {
return handleGetUidState(args, out, err);
} else if (args.size() == 1 && args[0] == String16("help")) {
printHelp(out);
@@ -720,14 +739,32 @@
return BAD_VALUE;
}
-status_t AudioPolicyService::handleSetUidState(Vector<String16>& args, int err) {
- PermissionController pc;
- int uid = pc.getPackageUid(args[1], 0);
- if (uid <= 0) {
- ALOGE("Unknown package: '%s'", String8(args[1]).string());
- dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+static status_t getUidForPackage(String16 packageName, int userId, /*inout*/uid_t& uid, int err) {
+ if (userId < 0) {
+ ALOGE("Invalid user: %d", userId);
+ dprintf(err, "Invalid user: %d\n", userId);
return BAD_VALUE;
}
+
+ PermissionController pc;
+ uid = pc.getPackageUid(packageName, 0);
+ if (uid <= 0) {
+ ALOGE("Unknown package: '%s'", String8(packageName).string());
+ dprintf(err, "Unknown package: '%s'\n", String8(packageName).string());
+ return BAD_VALUE;
+ }
+
+ uid = multiuser_get_uid(userId, uid);
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::handleSetUidState(Vector<String16>& args, int err) {
+ // Valid arg.size() is 3 or 5, args.size() is 5 with --user option.
+ if (!(args.size() == 3 || args.size() == 5)) {
+ printHelp(err);
+ return BAD_VALUE;
+ }
+
bool active = false;
if (args[2] == String16("active")) {
active = true;
@@ -735,30 +772,59 @@
ALOGE("Expected active or idle but got: '%s'", String8(args[2]).string());
return BAD_VALUE;
}
+
+ int userId = 0;
+ if (args.size() >= 5 && args[3] == String16("--user")) {
+ userId = atoi(String8(args[4]));
+ }
+
+ uid_t uid;
+ if (getUidForPackage(args[1], userId, uid, err) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+
mUidPolicy->addOverrideUid(uid, active);
return NO_ERROR;
}
status_t AudioPolicyService::handleResetUidState(Vector<String16>& args, int err) {
- PermissionController pc;
- int uid = pc.getPackageUid(args[1], 0);
- if (uid < 0) {
- ALOGE("Unknown package: '%s'", String8(args[1]).string());
- dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+ // Valid arg.size() is 2 or 4, args.size() is 4 with --user option.
+ if (!(args.size() == 2 || args.size() == 4)) {
+ printHelp(err);
return BAD_VALUE;
}
+
+ int userId = 0;
+ if (args.size() >= 4 && args[2] == String16("--user")) {
+ userId = atoi(String8(args[3]));
+ }
+
+ uid_t uid;
+ if (getUidForPackage(args[1], userId, uid, err) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+
mUidPolicy->removeOverrideUid(uid);
return NO_ERROR;
}
status_t AudioPolicyService::handleGetUidState(Vector<String16>& args, int out, int err) {
- PermissionController pc;
- int uid = pc.getPackageUid(args[1], 0);
- if (uid < 0) {
- ALOGE("Unknown package: '%s'", String8(args[1]).string());
- dprintf(err, "Unknown package: '%s'\n", String8(args[1]).string());
+ // Valid arg.size() is 2 or 4, args.size() is 4 with --user option.
+ if (!(args.size() == 2 || args.size() == 4)) {
+ printHelp(err);
return BAD_VALUE;
}
+
+ int userId = 0;
+ if (args.size() >= 4 && args[2] == String16("--user")) {
+ userId = atoi(String8(args[3]));
+ }
+
+ uid_t uid;
+ if (getUidForPackage(args[1], userId, uid, err) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+
if (mUidPolicy->isUidActive(uid)) {
return dprintf(out, "active\n");
} else {
@@ -768,9 +834,9 @@
status_t AudioPolicyService::printHelp(int out) {
return dprintf(out, "Audio policy service commands:\n"
- " get-uid-state <PACKAGE> gets the uid state\n"
- " set-uid-state <PACKAGE> <active|idle> overrides the uid state\n"
- " reset-uid-state <PACKAGE> clears the uid state override\n"
+ " get-uid-state <PACKAGE> [--user USER_ID] gets the uid state\n"
+ " set-uid-state <PACKAGE> <active|idle> [--user USER_ID] overrides the uid state\n"
+ " reset-uid-state <PACKAGE> [--user USER_ID] clears the uid state override\n"
" help print this message\n");
}
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 87aed41..c50a3c6 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -92,6 +92,7 @@
"libhardware",
"libhidlbase",
"libjpeg",
+ "libmedia_codeclist",
"libmedia_omx",
"libmemunreachable",
"libsensorprivacy",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index bdeb273..06c6996 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -153,8 +153,6 @@
mInitialized = true;
}
- CameraService::pingCameraServiceProxy();
-
mUidPolicy = new UidPolicy(this);
mUidPolicy->registerSelf();
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
@@ -164,6 +162,11 @@
ALOGE("%s: Failed to register default android.frameworks.cameraservice.service@1.0",
__FUNCTION__);
}
+
+ // This needs to be last call in this function, so that it's as close to
+ // ServiceManager::addService() as possible.
+ CameraService::pingCameraServiceProxy();
+ ALOGI("CameraService pinged cameraservice proxy");
}
status_t CameraService::enumerateProviders() {
@@ -1169,6 +1172,8 @@
clientPid,
states[states.size() - 1]);
+ resource_policy::ClientPriority clientPriority = clientDescriptor->getPriority();
+
// Find clients that would be evicted
auto evicted = mActiveClientManager.wouldEvict(clientDescriptor);
@@ -1186,8 +1191,7 @@
String8 msg = String8::format("%s : DENIED connect device %s client for package %s "
"(PID %d, score %d state %d) due to eviction policy", curTime.string(),
cameraId.string(), packageName.string(), clientPid,
- priorityScores[priorityScores.size() - 1],
- states[states.size() - 1]);
+ clientPriority.getScore(), clientPriority.getState());
for (auto& i : incompatibleClients) {
msg.appendFormat("\n - Blocked by existing device %s client for package %s"
@@ -1232,9 +1236,8 @@
i->getKey().string(), String8{clientSp->getPackageName()}.string(),
i->getOwnerId(), i->getPriority().getScore(),
i->getPriority().getState(), cameraId.string(),
- packageName.string(), clientPid,
- priorityScores[priorityScores.size() - 1],
- states[states.size() - 1]));
+ packageName.string(), clientPid, clientPriority.getScore(),
+ clientPriority.getState()));
// Notify the client of disconnection
clientSp->notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
@@ -1368,14 +1371,19 @@
Status ret = Status::ok();
String8 id = String8(cameraId);
sp<CameraDeviceClient> client = nullptr;
-
+ String16 clientPackageNameAdj = clientPackageName;
+ if (hardware::IPCThreadState::self()->isServingCall()) {
+ std::string vendorClient =
+ StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
+ clientPackageNameAdj = String16(vendorClient.c_str());
+ }
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
/*api1CameraId*/-1,
- CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
+ CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj,
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
- logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
+ logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageNameAdj),
ret.toString8());
return ret;
}
@@ -2397,11 +2405,7 @@
}
mClientPackageName = packages[0];
}
- if (hardware::IPCThreadState::self()->isServingCall()) {
- std::string vendorClient =
- StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
- mClientPackageName = String16(vendorClient.c_str());
- } else {
+ if (!hardware::IPCThreadState::self()->isServingCall()) {
mAppOpsManager = std::make_unique<AppOpsManager>();
}
}
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index 8ebaa2b..0b91016 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -247,7 +247,7 @@
return ret;
}
-status_t DepthCompositeStream::processInputFrame(const InputFrame &inputFrame) {
+status_t DepthCompositeStream::processInputFrame(nsecs_t ts, const InputFrame &inputFrame) {
status_t res;
sp<ANativeWindow> outputANW = mOutputSurface;
ANativeWindowBuffer *anb;
@@ -370,6 +370,13 @@
return NO_MEMORY;
}
+ res = native_window_set_buffers_timestamp(mOutputSurface.get(), ts);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)", __FUNCTION__,
+ getStreamId(), strerror(-res), res);
+ return res;
+ }
+
ALOGV("%s: Final jpeg size: %zu", __func__, finalJpegSize);
uint8_t* header = static_cast<uint8_t *> (dstBuffer) +
(gb->getWidth() - sizeof(struct camera3_jpeg_blob));
@@ -459,7 +466,7 @@
}
}
- auto res = processInputFrame(mPendingInputFrames[currentTs]);
+ auto res = processInputFrame(currentTs, mPendingInputFrames[currentTs]);
Mutex::Autolock l(mMutex);
if (res != OK) {
ALOGE("%s: Failed processing frame with timestamp: %" PRIu64 ": %s (%d)", __FUNCTION__,
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index 975c59b..28a7826 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -97,7 +97,7 @@
size_t maxJpegSize, uint8_t jpegQuality,
std::vector<std::unique_ptr<Item>>* items /*out*/);
std::unique_ptr<ImagingModel> getImagingModel();
- status_t processInputFrame(const InputFrame &inputFrame);
+ status_t processInputFrame(nsecs_t ts, const InputFrame &inputFrame);
// Buffer/Results handling
void compilePendingInputLocked();
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index 3d1235e..d21641c 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -1671,8 +1671,13 @@
ALOGE("CB_OUTPUT_FORMAT_CHANGED: format is expected.");
break;
}
-
- parent->onHeicFormatChanged(format);
+ // Here format is MediaCodec's internal copy of output format.
+ // Make a copy since onHeicFormatChanged() might modify it.
+ sp<AMessage> formatCopy;
+ if (format != nullptr) {
+ formatCopy = format->dup();
+ }
+ parent->onHeicFormatChanged(formatCopy);
break;
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 7f94e55..fdb5657 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -29,6 +29,7 @@
#include <future>
#include <inttypes.h>
#include <hardware/camera_common.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/ServiceManagement.h>
#include <functional>
#include <camera_metadata_hidden.h>
@@ -47,10 +48,6 @@
using std::literals::chrono_literals::operator""s;
namespace {
-// Hardcoded name for the passthrough HAL implementation, since it can't be discovered via the
-// service manager
-const std::string kLegacyProviderName("legacy/0");
-const std::string kExternalProviderName("external/0");
const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
} // anonymous namespace
@@ -62,6 +59,19 @@
CameraProviderManager::~CameraProviderManager() {
}
+hardware::hidl_vec<hardware::hidl_string>
+CameraProviderManager::HardwareServiceInteractionProxy::listServices() {
+ hardware::hidl_vec<hardware::hidl_string> ret;
+ auto manager = hardware::defaultServiceManager1_2();
+ if (manager != nullptr) {
+ manager->listManifestByInterface(provider::V2_4::ICameraProvider::descriptor,
+ [&ret](const hardware::hidl_vec<hardware::hidl_string> ®istered) {
+ ret = registered;
+ });
+ }
+ return ret;
+}
+
status_t CameraProviderManager::initialize(wp<CameraProviderManager::StatusListener> listener,
ServiceInteractionProxy* proxy) {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -84,9 +94,10 @@
return INVALID_OPERATION;
}
- // See if there's a passthrough HAL, but let's not complain if there's not
- addProviderLocked(kLegacyProviderName, /*expected*/ false);
- addProviderLocked(kExternalProviderName, /*expected*/ false);
+
+ for (const auto& instance : mServiceProxy->listServices()) {
+ this->addProviderLocked(instance);
+ }
IPCThreadState::self()->flushCommands();
@@ -1116,7 +1127,7 @@
return falseRet;
}
-status_t CameraProviderManager::addProviderLocked(const std::string& newProvider, bool expected) {
+status_t CameraProviderManager::addProviderLocked(const std::string& newProvider) {
for (const auto& providerInfo : mProviders) {
if (providerInfo->mProviderName == newProvider) {
ALOGW("%s: Camera provider HAL with name '%s' already registered", __FUNCTION__,
@@ -1129,13 +1140,9 @@
interface = mServiceProxy->getService(newProvider);
if (interface == nullptr) {
- if (expected) {
- ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
- newProvider.c_str());
- return BAD_VALUE;
- } else {
- return OK;
- }
+ ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
+ newProvider.c_str());
+ return BAD_VALUE;
}
sp<ProviderInfo> providerInfo = new ProviderInfo(newProvider, this);
@@ -2087,6 +2094,13 @@
return OK;
}
bool CameraProviderManager::ProviderInfo::DeviceInfo3::isAPI1Compatible() const {
+ // Do not advertise NIR cameras to API1 camera app.
+ camera_metadata_ro_entry cfa = mCameraCharacteristics.find(
+ ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT);
+ if (cfa.count == 1 && cfa.data.u8[0] == ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_NIR) {
+ return false;
+ }
+
bool isBackwardCompatible = false;
camera_metadata_ro_entry_t caps = mCameraCharacteristics.find(
ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index cd283b3..954c0d9 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -78,6 +78,7 @@
¬ification) = 0;
virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
const std::string &serviceName) = 0;
+ virtual hardware::hidl_vec<hardware::hidl_string> listServices() = 0;
virtual ~ServiceInteractionProxy() {}
};
@@ -95,6 +96,8 @@
const std::string &serviceName) override {
return hardware::camera::provider::V2_4::ICameraProvider::getService(serviceName);
}
+
+ virtual hardware::hidl_vec<hardware::hidl_string> listServices() override;
};
/**
@@ -270,6 +273,7 @@
bool isLogicalCamera(const std::string& id, std::vector<std::string>* physicalCameraIds);
bool isPublicallyHiddenSecureCamera(const std::string& id) const;
+
bool isHiddenPhysicalCamera(const std::string& cameraId) const;
static const float kDepthARTolerance;
@@ -567,7 +571,7 @@
hardware::hidl_version minVersion = hardware::hidl_version{0,0},
hardware::hidl_version maxVersion = hardware::hidl_version{1000,0}) const;
- status_t addProviderLocked(const std::string& newProvider, bool expected = true);
+ status_t addProviderLocked(const std::string& newProvider);
status_t removeProvider(const std::string& provider);
sp<StatusListener> getStatusListener() const;
diff --git a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
index 3c90de0..94541d8 100644
--- a/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
+++ b/services/camera/libcameraservice/common/DepthPhotoProcessor.cpp
@@ -419,7 +419,7 @@
std::vector<std::unique_ptr<Item>> items;
std::vector<std::unique_ptr<Camera>> cameraList;
- auto image = Image::FromDataForPrimaryImage("android/mainimage", &items);
+ auto image = Image::FromDataForPrimaryImage("image/jpeg", &items);
std::unique_ptr<CameraParams> cameraParams(new CameraParams(std::move(image)));
if (cameraParams == nullptr) {
ALOGE("%s: Failed to initialize camera parameters", __FUNCTION__);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index a8e80fa..4227a3b 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -29,6 +29,9 @@
#define CLOGE(fmt, ...) ALOGE("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
##__VA_ARGS__)
+#define CLOGW(fmt, ...) ALOGW("Camera %s: %s: " fmt, mId.string(), __FUNCTION__, \
+ ##__VA_ARGS__)
+
// Convenience macros for transitioning to the error state
#define SET_ERR(fmt, ...) setErrorState( \
"%s: " fmt, __FUNCTION__, \
@@ -3267,14 +3270,19 @@
ALOGVV("%s: removed frame %d from InFlightMap", __FUNCTION__, frameNumber);
}
- // Sanity check - if we have too many in-flight frames, something has
- // likely gone wrong
- if (!mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > kInFlightWarnLimit) {
- CLOGE("In-flight list too large: %zu", mInFlightMap.size());
- } else if (mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() >
- kInFlightWarnLimitHighSpeed) {
- CLOGE("In-flight list too large for high speed configuration: %zu",
- mInFlightMap.size());
+ // Sanity check - if we have too many in-flight frames with long total inflight duration,
+ // something has likely gone wrong. This might still be legit only if application send in
+ // a long burst of long exposure requests.
+ if (mExpectedInflightDuration > kMinWarnInflightDuration) {
+ if (!mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() > kInFlightWarnLimit) {
+ CLOGW("In-flight list too large: %zu, total inflight duration %" PRIu64,
+ mInFlightMap.size(), mExpectedInflightDuration);
+ } else if (mIsConstrainedHighSpeedConfiguration && mInFlightMap.size() >
+ kInFlightWarnLimitHighSpeed) {
+ CLOGW("In-flight list too large for high speed configuration: %zu,"
+ "total inflight duration %" PRIu64,
+ mInFlightMap.size(), mExpectedInflightDuration);
+ }
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 6e8ac84..cae34ce 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -227,6 +227,7 @@
static const size_t kDumpLockAttempts = 10;
static const size_t kDumpSleepDuration = 100000; // 0.10 sec
static const nsecs_t kActiveTimeout = 500000000; // 500 ms
+ static const nsecs_t kMinWarnInflightDuration = 5000000000; // 5 s
static const size_t kInFlightWarnLimit = 30;
static const size_t kInFlightWarnLimitHighSpeed = 256; // batch size 32 * pipe depth 8
static const nsecs_t kDefaultExpectedDuration = 100000000; // 100 ms
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index f47e5a5..78d737d 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -205,6 +205,11 @@
return mTestCameraProvider;
}
+ virtual hardware::hidl_vec<hardware::hidl_string> listServices() override {
+ hardware::hidl_vec<hardware::hidl_string> ret = {"test/0"};
+ return ret;
+ }
+
};
struct TestStatusListener : public CameraProviderManager::StatusListener {
@@ -231,37 +236,24 @@
vendorSection);
serviceProxy.setProvider(provider);
+ int numProviders = static_cast<int>(serviceProxy.listServices().size());
+
res = providerManager->initialize(statusListener, &serviceProxy);
ASSERT_EQ(res, OK) << "Unable to initialize provider manager";
// Check that both "legacy" and "external" providers (really the same object) are called
// once for all the init methods
- EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], 2) <<
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::SET_CALLBACK], numProviders) <<
"Only one call to setCallback per provider expected during init";
- EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], 2) <<
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_VENDOR_TAGS], numProviders) <<
"Only one call to getVendorTags per provider expected during init";
- EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED], 2) <<
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::IS_SET_TORCH_MODE_SUPPORTED],
+ numProviders) <<
"Only one call to isSetTorchModeSupported per provider expected during init";
- EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], 2) <<
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::GET_CAMERA_ID_LIST], numProviders) <<
"Only one call to getCameraIdList per provider expected during init";
- EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], 2) <<
+ EXPECT_EQ(provider->mCalledCounter[TestICameraProvider::NOTIFY_DEVICE_STATE], numProviders) <<
"Only one call to notifyDeviceState per provider expected during init";
- std::string legacyInstanceName = "legacy/0";
- std::string externalInstanceName = "external/0";
- bool gotLegacy = false;
- bool gotExternal = false;
- EXPECT_EQ(2u, serviceProxy.mLastRequestedServiceNames.size()) <<
- "Only two service queries expected to be seen by hardware service manager";
-
- for (auto& serviceName : serviceProxy.mLastRequestedServiceNames) {
- if (serviceName == legacyInstanceName) gotLegacy = true;
- if (serviceName == externalInstanceName) gotExternal = true;
- }
- ASSERT_TRUE(gotLegacy) <<
- "Legacy instance not requested from service manager";
- ASSERT_TRUE(gotExternal) <<
- "External instance not requested from service manager";
-
hardware::hidl_string testProviderFqInterfaceName =
"android.hardware.camera.provider@2.4::ICameraProvider";
hardware::hidl_string testProviderInstanceName = "test/0";
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index f668c33..6a82b1b 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -21,6 +21,7 @@
#include "minijail.h"
#include <binder/ProcessState.h>
+#include <cutils/properties.h>
#include <hidl/HidlTransportSupport.h>
#include <media/stagefright/omx/1.0/Omx.h>
#include <media/stagefright/omx/1.0/OmxStore.h>
@@ -57,7 +58,8 @@
} else {
LOG(INFO) << "IOmx HAL service created.";
}
- sp<IOmxStore> omxStore = new implementation::OmxStore(omx);
+ sp<IOmxStore> omxStore = new implementation::OmxStore(
+ property_get_int64("vendor.media.omx", 1) ? omx : nullptr);
if (omxStore == nullptr) {
LOG(ERROR) << "Cannot create IOmxStore HAL service.";
} else if (omxStore->registerAsService() != OK) {
diff --git a/services/mediacodec/registrant/Android.bp b/services/mediacodec/registrant/Android.bp
index 17c2e02..fa5bc4a 100644
--- a/services/mediacodec/registrant/Android.bp
+++ b/services/mediacodec/registrant/Android.bp
@@ -42,7 +42,8 @@
"libcodec2_soft_opusenc",
"libcodec2_soft_vp8dec",
"libcodec2_soft_vp9dec",
- "libcodec2_soft_av1dec",
+ // "libcodec2_soft_av1dec_aom", // replaced by the gav1 implementation
+ "libcodec2_soft_av1dec_gav1",
"libcodec2_soft_vp8enc",
"libcodec2_soft_vp9enc",
"libcodec2_soft_rawdec",
diff --git a/services/mediaextractor/Android.bp b/services/mediaextractor/Android.bp
index b812244..e906500 100644
--- a/services/mediaextractor/Android.bp
+++ b/services/mediaextractor/Android.bp
@@ -8,6 +8,7 @@
srcs: ["MediaExtractorService.cpp"],
shared_libs: [
+ "libdatasource",
"libmedia",
"libstagefright",
"libbinder",
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
index 36e084b..ac6b771 100644
--- a/services/mediaextractor/MediaExtractorService.cpp
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -20,8 +20,8 @@
#include <utils/Vector.h>
+#include <datasource/DataSourceFactory.h>
#include <media/DataSource.h>
-#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/RemoteDataSource.h>
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 28bfd3f..bdcd5e4 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -21,8 +21,11 @@
#include <binder/IMediaResourceMonitor.h>
#include <binder/IServiceManager.h>
+#include <cutils/sched_policy.h>
#include <dirent.h>
#include <media/stagefright/ProcessInfo.h>
+#include <mediautils/BatteryNotifier.h>
+#include <mediautils/SchedulingPolicyService.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -31,8 +34,7 @@
#include "ResourceManagerService.h"
#include "ServiceLog.h"
-#include "mediautils/SchedulingPolicyService.h"
-#include <cutils/sched_policy.h>
+
namespace android {
namespace {
@@ -69,9 +71,9 @@
return itemsStr;
}
-static bool hasResourceType(MediaResource::Type type, const Vector<MediaResource>& resources) {
- for (size_t i = 0; i < resources.size(); ++i) {
- if (resources[i].mType == type) {
+static bool hasResourceType(MediaResource::Type type, const ResourceList& resources) {
+ for (auto it = resources.begin(); it != resources.end(); it++) {
+ if (it->second.mType == type) {
return true;
}
}
@@ -101,20 +103,22 @@
}
static ResourceInfo& getResourceInfoForEdit(
+ uid_t uid,
int64_t clientId,
const sp<IResourceManagerClient>& client,
ResourceInfos& infos) {
- for (size_t i = 0; i < infos.size(); ++i) {
- if (infos[i].clientId == clientId) {
- return infos.editItemAt(i);
- }
+ ssize_t index = infos.indexOfKey(clientId);
+
+ if (index < 0) {
+ ResourceInfo info;
+ info.uid = uid;
+ info.clientId = clientId;
+ info.client = client;
+
+ index = infos.add(clientId, info);
}
- ResourceInfo info;
- info.clientId = clientId;
- info.client = client;
- info.cpuBoost = false;
- infos.push_back(info);
- return infos.editItemAt(infos.size() - 1);
+
+ return infos.editValueAt(index);
}
static void notifyResourceGranted(int pid, const Vector<MediaResource> &resources) {
@@ -181,10 +185,10 @@
snprintf(buffer, SIZE, " Name: %s\n", infos[j].client->getName().string());
result.append(buffer);
- Vector<MediaResource> resources = infos[j].resources;
+ const ResourceList &resources = infos[j].resources;
result.append(" Resources:\n");
- for (size_t k = 0; k < resources.size(); ++k) {
- snprintf(buffer, SIZE, " %s\n", resources[k].toString().string());
+ for (auto it = resources.begin(); it != resources.end(); it++) {
+ snprintf(buffer, SIZE, " %s\n", it->second.toString().string());
result.append(buffer);
}
}
@@ -196,15 +200,45 @@
return OK;
}
-ResourceManagerService::ResourceManagerService()
- : ResourceManagerService(new ProcessInfo()) {}
+struct SystemCallbackImpl :
+ public ResourceManagerService::SystemCallbackInterface {
+ SystemCallbackImpl() {}
-ResourceManagerService::ResourceManagerService(sp<ProcessInfoInterface> processInfo)
+ virtual void noteStartVideo(int uid) override {
+ BatteryNotifier::getInstance().noteStartVideo(uid);
+ }
+ virtual void noteStopVideo(int uid) override {
+ BatteryNotifier::getInstance().noteStopVideo(uid);
+ }
+ virtual void noteResetVideo() override {
+ BatteryNotifier::getInstance().noteResetVideo();
+ }
+ virtual bool requestCpusetBoost(
+ bool enable, const sp<IInterface> &client) override {
+ return android::requestCpusetBoost(enable, client);
+ }
+
+protected:
+ virtual ~SystemCallbackImpl() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(SystemCallbackImpl);
+};
+
+ResourceManagerService::ResourceManagerService()
+ : ResourceManagerService(new ProcessInfo(), new SystemCallbackImpl()) {}
+
+ResourceManagerService::ResourceManagerService(
+ const sp<ProcessInfoInterface> &processInfo,
+ const sp<SystemCallbackInterface> &systemResource)
: mProcessInfo(processInfo),
+ mSystemCB(systemResource),
mServiceLog(new ServiceLog()),
mSupportsMultipleSecureCodecs(true),
mSupportsSecureWithNonSecureCodec(true),
- mCpuBoostCount(0) {}
+ mCpuBoostCount(0) {
+ mSystemCB->noteResetVideo();
+}
ResourceManagerService::~ResourceManagerService() {}
@@ -224,8 +258,41 @@
}
}
+void ResourceManagerService::onFirstAdded(
+ const MediaResource& resource, const ResourceInfo& clientInfo) {
+ // first time added
+ if (resource.mType == MediaResource::kCpuBoost
+ && resource.mSubType == MediaResource::kUnspecifiedSubType) {
+ // Request it on every new instance of kCpuBoost, as the media.codec
+ // could have died, if we only do it the first time subsequent instances
+ // never gets the boost.
+ if (mSystemCB->requestCpusetBoost(true, this) != OK) {
+ ALOGW("couldn't request cpuset boost");
+ }
+ mCpuBoostCount++;
+ } else if (resource.mType == MediaResource::kBattery
+ && resource.mSubType == MediaResource::kVideoCodec) {
+ mSystemCB->noteStartVideo(clientInfo.uid);
+ }
+}
+
+void ResourceManagerService::onLastRemoved(
+ const MediaResource& resource, const ResourceInfo& clientInfo) {
+ if (resource.mType == MediaResource::kCpuBoost
+ && resource.mSubType == MediaResource::kUnspecifiedSubType
+ && mCpuBoostCount > 0) {
+ if (--mCpuBoostCount == 0) {
+ mSystemCB->requestCpusetBoost(false, this);
+ }
+ } else if (resource.mType == MediaResource::kBattery
+ && resource.mSubType == MediaResource::kVideoCodec) {
+ mSystemCB->noteStopVideo(clientInfo.uid);
+ }
+}
+
void ResourceManagerService::addResource(
int pid,
+ int uid,
int64_t clientId,
const sp<IResourceManagerClient> client,
const Vector<MediaResource> &resources) {
@@ -239,20 +306,15 @@
return;
}
ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
- ResourceInfo& info = getResourceInfoForEdit(clientId, client, infos);
- // TODO: do the merge instead of append.
- info.resources.appendVector(resources);
+ ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
for (size_t i = 0; i < resources.size(); ++i) {
- if (resources[i].mType == MediaResource::kCpuBoost && !info.cpuBoost) {
- info.cpuBoost = true;
- // Request it on every new instance of kCpuBoost, as the media.codec
- // could have died, if we only do it the first time subsequent instances
- // never gets the boost.
- if (requestCpusetBoost(true, this) != OK) {
- ALOGW("couldn't request cpuset boost");
- }
- mCpuBoostCount++;
+ const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+ if (info.resources.find(resType) == info.resources.end()) {
+ onFirstAdded(resources[i], info);
+ info.resources[resType] = resources[i];
+ } else {
+ info.resources[resType].mValue += resources[i].mValue;
}
}
if (info.deathNotifier == nullptr) {
@@ -262,7 +324,48 @@
notifyResourceGranted(pid, resources);
}
-void ResourceManagerService::removeResource(int pid, int64_t clientId) {
+void ResourceManagerService::removeResource(int pid, int64_t clientId,
+ const Vector<MediaResource> &resources) {
+ String8 log = String8::format("removeResource(pid %d, clientId %lld, resources %s)",
+ pid, (long long) clientId, getString(resources).string());
+ mServiceLog->add(log);
+
+ Mutex::Autolock lock(mLock);
+ if (!mProcessInfo->isValidPid(pid)) {
+ ALOGE("Rejected removeResource call with invalid pid.");
+ return;
+ }
+ ssize_t index = mMap.indexOfKey(pid);
+ if (index < 0) {
+ ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
+ return;
+ }
+ ResourceInfos &infos = mMap.editValueAt(index);
+
+ index = infos.indexOfKey(clientId);
+ if (index < 0) {
+ ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
+ return;
+ }
+
+ ResourceInfo &info = infos.editValueAt(index);
+
+ for (size_t i = 0; i < resources.size(); ++i) {
+ const auto resType = std::make_pair(resources[i].mType, resources[i].mSubType);
+ // ignore if we don't have it
+ if (info.resources.find(resType) != info.resources.end()) {
+ MediaResource &resource = info.resources[resType];
+ if (resource.mValue > resources[i].mValue) {
+ resource.mValue -= resources[i].mValue;
+ } else {
+ onLastRemoved(resources[i], info);
+ info.resources.erase(resType);
+ }
+ }
+ }
+}
+
+void ResourceManagerService::removeClient(int pid, int64_t clientId) {
removeResource(pid, clientId, true);
}
@@ -282,24 +385,22 @@
ALOGV("removeResource: didn't find pid %d for clientId %lld", pid, (long long) clientId);
return;
}
- bool found = false;
ResourceInfos &infos = mMap.editValueAt(index);
- for (size_t j = 0; j < infos.size(); ++j) {
- if (infos[j].clientId == clientId) {
- if (infos[j].cpuBoost && mCpuBoostCount > 0) {
- if (--mCpuBoostCount == 0) {
- requestCpusetBoost(false, this);
- }
- }
- IInterface::asBinder(infos[j].client)->unlinkToDeath(infos[j].deathNotifier);
- j = infos.removeAt(j);
- found = true;
- break;
- }
+
+ index = infos.indexOfKey(clientId);
+ if (index < 0) {
+ ALOGV("removeResource: didn't find clientId %lld", (long long) clientId);
+ return;
}
- if (!found) {
- ALOGV("didn't find client");
+
+ const ResourceInfo &info = infos[index];
+ for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
+ onLastRemoved(it->second, info);
}
+
+ IInterface::asBinder(info.client)->unlinkToDeath(info.deathNotifier);
+
+ infos.removeItemsAt(index);
}
void ResourceManagerService::getClientForResource_l(
@@ -410,7 +511,7 @@
ResourceInfos &infos = mMap.editValueAt(i);
for (size_t j = 0; j < infos.size();) {
if (infos[j].client == failedClient) {
- j = infos.removeAt(j);
+ j = infos.removeItemsAt(j);
found = true;
} else {
++j;
@@ -538,11 +639,12 @@
uint64_t largestValue = 0;
const ResourceInfos &infos = mMap.valueAt(index);
for (size_t i = 0; i < infos.size(); ++i) {
- Vector<MediaResource> resources = infos[i].resources;
- for (size_t j = 0; j < resources.size(); ++j) {
- if (resources[j].mType == type) {
- if (resources[j].mValue > largestValue) {
- largestValue = resources[j].mValue;
+ const ResourceList &resources = infos[i].resources;
+ for (auto it = resources.begin(); it != resources.end(); it++) {
+ const MediaResource &resource = it->second;
+ if (resource.mType == type) {
+ if (resource.mValue > largestValue) {
+ largestValue = resource.mValue;
clientTemp = infos[i].client;
}
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 82d2a0b..f086dc3 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -33,15 +33,17 @@
class ServiceLog;
struct ProcessInfoInterface;
+typedef std::map<std::pair<MediaResource::Type, MediaResource::SubType>, MediaResource> ResourceList;
struct ResourceInfo {
int64_t clientId;
+ uid_t uid;
sp<IResourceManagerClient> client;
sp<IBinder::DeathRecipient> deathNotifier;
- Vector<MediaResource> resources;
- bool cpuBoost;
+ ResourceList resources;
};
-typedef Vector<ResourceInfo> ResourceInfos;
+// TODO: convert these to std::map
+typedef KeyedVector<int64_t, ResourceInfo> ResourceInfos;
typedef KeyedVector<int, ResourceInfos> PidResourceInfosMap;
class ResourceManagerService
@@ -49,23 +51,37 @@
public BnResourceManagerService
{
public:
+ struct SystemCallbackInterface : public RefBase {
+ virtual void noteStartVideo(int uid) = 0;
+ virtual void noteStopVideo(int uid) = 0;
+ virtual void noteResetVideo() = 0;
+ virtual bool requestCpusetBoost(
+ bool enable, const sp<IInterface> &client) = 0;
+ };
+
static char const *getServiceName() { return "media.resource_manager"; }
virtual status_t dump(int fd, const Vector<String16>& args);
ResourceManagerService();
- explicit ResourceManagerService(sp<ProcessInfoInterface> processInfo);
+ explicit ResourceManagerService(
+ const sp<ProcessInfoInterface> &processInfo,
+ const sp<SystemCallbackInterface> &systemResource);
// IResourceManagerService interface
virtual void config(const Vector<MediaResourcePolicy> &policies);
virtual void addResource(
int pid,
+ int uid,
int64_t clientId,
const sp<IResourceManagerClient> client,
const Vector<MediaResource> &resources);
- virtual void removeResource(int pid, int64_t clientId);
+ virtual void removeResource(int pid, int64_t clientId,
+ const Vector<MediaResource> &resources);
+
+ virtual void removeClient(int pid, int64_t clientId);
// Tries to reclaim resource from processes with lower priority than the calling process
// according to the requested resources.
@@ -107,8 +123,12 @@
void getClientForResource_l(
int callingPid, const MediaResource *res, Vector<sp<IResourceManagerClient>> *clients);
+ void onFirstAdded(const MediaResource& res, const ResourceInfo& clientInfo);
+ void onLastRemoved(const MediaResource& res, const ResourceInfo& clientInfo);
+
mutable Mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
+ sp<SystemCallbackInterface> mSystemCB;
sp<ServiceLog> mServiceLog;
PidResourceInfosMap mMap;
bool mSupportsMultipleSecureCodecs;
diff --git a/services/mediaresourcemanager/TEST_MAPPING b/services/mediaresourcemanager/TEST_MAPPING
new file mode 100644
index 0000000..418b159
--- /dev/null
+++ b/services/mediaresourcemanager/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "ResourceManagerService_test"
+ },
+ {
+ "name": "ServiceLog_test"
+ }
+ ]
+}
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 70e8833..543c87c 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -2,6 +2,7 @@
cc_test {
name: "ResourceManagerService_test",
srcs: ["ResourceManagerService_test.cpp"],
+ test_suites: ["device-tests"],
shared_libs: [
"libbinder",
"liblog",
@@ -23,6 +24,7 @@
cc_test {
name: "ServiceLog_test",
srcs: ["ServiceLog_test.cpp"],
+ test_suites: ["device-tests"],
shared_libs: [
"liblog",
"libmedia",
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index ed0b0ef..ae97ec8 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -52,13 +52,69 @@
DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
};
+struct TestSystemCallback :
+ public ResourceManagerService::SystemCallbackInterface {
+ TestSystemCallback() :
+ mLastEvent({EventType::INVALID, 0}), mEventCount(0) {}
+
+ enum EventType {
+ INVALID = -1,
+ VIDEO_ON = 0,
+ VIDEO_OFF = 1,
+ VIDEO_RESET = 2,
+ CPUSET_ENABLE = 3,
+ CPUSET_DISABLE = 4,
+ };
+
+ struct EventEntry {
+ EventType type;
+ int arg;
+ };
+
+ virtual void noteStartVideo(int uid) override {
+ mLastEvent = {EventType::VIDEO_ON, uid};
+ mEventCount++;
+ }
+
+ virtual void noteStopVideo(int uid) override {
+ mLastEvent = {EventType::VIDEO_OFF, uid};
+ mEventCount++;
+ }
+
+ virtual void noteResetVideo() override {
+ mLastEvent = {EventType::VIDEO_RESET, 0};
+ mEventCount++;
+ }
+
+ virtual bool requestCpusetBoost(
+ bool enable, const sp<IInterface> &/*client*/) override {
+ mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
+ mEventCount++;
+ return true;
+ }
+
+ size_t eventCount() { return mEventCount; }
+ EventType lastEventType() { return mLastEvent.type; }
+ EventEntry lastEvent() { return mLastEvent; }
+
+protected:
+ virtual ~TestSystemCallback() {}
+
+private:
+ EventEntry mLastEvent;
+ size_t mEventCount;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TestSystemCallback);
+};
+
+
struct TestClient : public BnResourceManagerClient {
TestClient(int pid, sp<ResourceManagerService> service)
: mReclaimed(false), mPid(pid), mService(service) {}
virtual bool reclaimResource() {
sp<IResourceManagerClient> client(this);
- mService->removeResource(mPid, (int64_t) client.get());
+ mService->removeClient(mPid, (int64_t) client.get());
mReclaimed = true;
return true;
}
@@ -86,16 +142,26 @@
};
static const int kTestPid1 = 30;
+static const int kTestUid1 = 1010;
+
static const int kTestPid2 = 20;
+static const int kTestUid2 = 1011;
static const int kLowPriorityPid = 40;
static const int kMidPriorityPid = 25;
static const int kHighPriorityPid = 10;
+using EventType = TestSystemCallback::EventType;
+using EventEntry = TestSystemCallback::EventEntry;
+bool operator== (const EventEntry& lhs, const EventEntry& rhs) {
+ return lhs.type == rhs.type && lhs.arg == rhs.arg;
+}
+
class ResourceManagerServiceTest : public ::testing::Test {
public:
ResourceManagerServiceTest()
- : mService(new ResourceManagerService(new TestProcessInfo)),
+ : mSystemCB(new TestSystemCallback()),
+ mService(new ResourceManagerService(new TestProcessInfo, mSystemCB)),
mTestClient1(new TestClient(kTestPid1, mService)),
mTestClient2(new TestClient(kTestPid2, mService)),
mTestClient3(new TestClient(kTestPid2, mService)) {
@@ -103,20 +169,21 @@
protected:
static bool isEqualResources(const Vector<MediaResource> &resources1,
- const Vector<MediaResource> &resources2) {
- if (resources1.size() != resources2.size()) {
- return false;
- }
+ const ResourceList &resources2) {
+ // convert resource1 to ResourceList
+ ResourceList r1;
for (size_t i = 0; i < resources1.size(); ++i) {
- if (resources1[i] != resources2[i]) {
- return false;
- }
+ const auto resType = std::make_pair(resources1[i].mType, resources1[i].mSubType);
+ r1[resType] = resources1[i];
}
- return true;
+ return r1 == resources2;
}
- static void expectEqResourceInfo(const ResourceInfo &info, sp<IResourceManagerClient> client,
+ static void expectEqResourceInfo(const ResourceInfo &info,
+ int uid,
+ sp<IResourceManagerClient> client,
const Vector<MediaResource> &resources) {
+ EXPECT_EQ(uid, info.uid);
EXPECT_EQ(client, info.client);
EXPECT_TRUE(isEqualResources(resources, info.resources));
}
@@ -153,24 +220,24 @@
// kTestPid1 mTestClient1
Vector<MediaResource> resources1;
resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
- mService->addResource(kTestPid1, getId(mTestClient1), mTestClient1, resources1);
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
Vector<MediaResource> resources11;
resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
- mService->addResource(kTestPid1, getId(mTestClient1), mTestClient1, resources11);
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
// kTestPid2 mTestClient2
Vector<MediaResource> resources2;
resources2.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
resources2.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
- mService->addResource(kTestPid2, getId(mTestClient2), mTestClient2, resources2);
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
// kTestPid2 mTestClient3
Vector<MediaResource> resources3;
- mService->addResource(kTestPid2, getId(mTestClient3), mTestClient3, resources3);
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
resources3.push_back(MediaResource(MediaResource::kSecureCodec, 1));
resources3.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
- mService->addResource(kTestPid2, getId(mTestClient3), mTestClient3, resources3);
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources3);
const PidResourceInfosMap &map = mService->mMap;
EXPECT_EQ(2u, map.size());
@@ -178,14 +245,14 @@
ASSERT_GE(index1, 0);
const ResourceInfos &infos1 = map[index1];
EXPECT_EQ(1u, infos1.size());
- expectEqResourceInfo(infos1[0], mTestClient1, resources1);
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, resources1);
ssize_t index2 = map.indexOfKey(kTestPid2);
ASSERT_GE(index2, 0);
const ResourceInfos &infos2 = map[index2];
EXPECT_EQ(2u, infos2.size());
- expectEqResourceInfo(infos2[0], mTestClient2, resources2);
- expectEqResourceInfo(infos2[1], mTestClient3, resources3);
+ expectEqResourceInfo(infos2.valueFor(getId(mTestClient2)), kTestUid2, mTestClient2, resources2);
+ expectEqResourceInfo(infos2.valueFor(getId(mTestClient3)), kTestUid2, mTestClient3, resources3);
}
void testConfig() {
@@ -219,10 +286,84 @@
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
}
+ void testCombineResource() {
+ // kTestPid1 mTestClient1
+ Vector<MediaResource> resources1;
+ resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ Vector<MediaResource> resources11;
+ resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
+
+ const PidResourceInfosMap &map = mService->mMap;
+ EXPECT_EQ(1u, map.size());
+ ssize_t index1 = map.indexOfKey(kTestPid1);
+ ASSERT_GE(index1, 0);
+ const ResourceInfos &infos1 = map[index1];
+ EXPECT_EQ(1u, infos1.size());
+
+ // test adding existing types to combine values
+ resources1.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ Vector<MediaResource> expected;
+ expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
+ expected.push_back(MediaResource(MediaResource::kGraphicMemory, 300));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ // test adding new types (including types that differs only in subType)
+ resources11.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
+ resources11.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
+
+ expected.clear();
+ expected.push_back(MediaResource(MediaResource::kSecureCodec, 2));
+ expected.push_back(MediaResource(MediaResource::kNonSecureCodec, 1));
+ expected.push_back(MediaResource(MediaResource::kSecureCodec, MediaResource::kVideoCodec, 1));
+ expected.push_back(MediaResource(MediaResource::kGraphicMemory, 500));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ }
+
void testRemoveResource() {
+ // kTestPid1 mTestClient1
+ Vector<MediaResource> resources1;
+ resources1.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+
+ Vector<MediaResource> resources11;
+ resources11.push_back(MediaResource(MediaResource::kGraphicMemory, 200));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources11);
+
+ const PidResourceInfosMap &map = mService->mMap;
+ EXPECT_EQ(1u, map.size());
+ ssize_t index1 = map.indexOfKey(kTestPid1);
+ ASSERT_GE(index1, 0);
+ const ResourceInfos &infos1 = map[index1];
+ EXPECT_EQ(1u, infos1.size());
+
+ // test partial removal
+ resources11.editItemAt(0).mValue = 100;
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
+
+ Vector<MediaResource> expected;
+ expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ expected.push_back(MediaResource(MediaResource::kGraphicMemory, 100));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+
+ // test complete removal with overshoot value
+ resources11.editItemAt(0).mValue = 1000;
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources11);
+
+ expected.clear();
+ expected.push_back(MediaResource(MediaResource::kSecureCodec, 1));
+ expectEqResourceInfo(infos1.valueFor(getId(mTestClient1)), kTestUid1, mTestClient1, expected);
+ }
+
+ void testRemoveClient() {
addResource();
- mService->removeResource(kTestPid2, getId(mTestClient2));
+ mService->removeClient(kTestPid2, getId(mTestClient2));
const PidResourceInfosMap &map = mService->mMap;
EXPECT_EQ(2u, map.size());
@@ -231,6 +372,7 @@
EXPECT_EQ(1u, infos1.size());
EXPECT_EQ(1u, infos2.size());
// mTestClient2 has been removed.
+ // (OK to use infos2[0] as there is only 1 entry)
EXPECT_EQ(mTestClient3, infos2[0].client);
}
@@ -246,6 +388,7 @@
EXPECT_TRUE(mService->getAllClients_l(kHighPriorityPid, type, &clients));
EXPECT_EQ(2u, clients.size());
+ // (OK to require ordering in clients[], as the pid map is sorted)
EXPECT_EQ(mTestClient3, clients[0]);
EXPECT_EQ(mTestClient1, clients[1]);
}
@@ -438,7 +581,7 @@
verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
// clean up client 3 which still left
- mService->removeResource(kTestPid2, getId(mTestClient3));
+ mService->removeClient(kTestPid2, getId(mTestClient3));
}
}
@@ -498,6 +641,84 @@
EXPECT_TRUE(mService->isCallingPriorityHigher_l(99, 100));
}
+ void testBatteryStats() {
+ // reset should always be called when ResourceManagerService is created (restarted)
+ EXPECT_EQ(1u, mSystemCB->eventCount());
+ EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
+
+ // new client request should cause VIDEO_ON
+ Vector<MediaResource> resources1;
+ resources1.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 1));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+ EXPECT_EQ(2u, mSystemCB->eventCount());
+ EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid1}), mSystemCB->lastEvent());
+
+ // each client should only cause 1 VIDEO_ON
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+ EXPECT_EQ(2u, mSystemCB->eventCount());
+
+ // new client request should cause VIDEO_ON
+ Vector<MediaResource> resources2;
+ resources2.push_back(MediaResource(MediaResource::kBattery, MediaResource::kVideoCodec, 2));
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
+ EXPECT_EQ(3u, mSystemCB->eventCount());
+ EXPECT_EQ(EventEntry({EventType::VIDEO_ON, kTestUid2}), mSystemCB->lastEvent());
+
+ // partially remove mTestClient1's request, shouldn't be any VIDEO_OFF
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources1);
+ EXPECT_EQ(3u, mSystemCB->eventCount());
+
+ // remove mTestClient1's request, should be VIDEO_OFF for kTestUid1
+ // (use resource2 to test removing more instances than previously requested)
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources2);
+ EXPECT_EQ(4u, mSystemCB->eventCount());
+ EXPECT_EQ(EventEntry({EventType::VIDEO_OFF, kTestUid1}), mSystemCB->lastEvent());
+
+ // remove mTestClient2, should be VIDEO_OFF for kTestUid2
+ mService->removeClient(kTestPid2, getId(mTestClient2));
+ EXPECT_EQ(5u, mSystemCB->eventCount());
+ EXPECT_EQ(EventEntry({EventType::VIDEO_OFF, kTestUid2}), mSystemCB->lastEvent());
+ }
+
+ void testCpusetBoost() {
+ // reset should always be called when ResourceManagerService is created (restarted)
+ EXPECT_EQ(1u, mSystemCB->eventCount());
+ EXPECT_EQ(EventType::VIDEO_RESET, mSystemCB->lastEventType());
+
+ // new client request should cause CPUSET_ENABLE
+ Vector<MediaResource> resources1;
+ resources1.push_back(MediaResource(MediaResource::kCpuBoost, 1));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+ EXPECT_EQ(2u, mSystemCB->eventCount());
+ EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
+
+ // each client should only cause 1 CPUSET_ENABLE
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources1);
+ EXPECT_EQ(2u, mSystemCB->eventCount());
+
+ // new client request should cause CPUSET_ENABLE
+ Vector<MediaResource> resources2;
+ resources2.push_back(MediaResource(MediaResource::kCpuBoost, 2));
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources2);
+ EXPECT_EQ(3u, mSystemCB->eventCount());
+ EXPECT_EQ(EventType::CPUSET_ENABLE, mSystemCB->lastEventType());
+
+ // remove mTestClient2 should not cause CPUSET_DISABLE, mTestClient1 still active
+ mService->removeClient(kTestPid2, getId(mTestClient2));
+ EXPECT_EQ(3u, mSystemCB->eventCount());
+
+ // remove 1 cpuboost from mTestClient1, should not be CPUSET_DISABLE (still 1 left)
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources1);
+ EXPECT_EQ(3u, mSystemCB->eventCount());
+
+ // remove 2 cpuboost from mTestClient1, should be CPUSET_DISABLE
+ // (use resource2 to test removing more than previously requested)
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources2);
+ EXPECT_EQ(4u, mSystemCB->eventCount());
+ EXPECT_EQ(EventType::CPUSET_DISABLE, mSystemCB->lastEventType());
+ }
+
+ sp<TestSystemCallback> mSystemCB;
sp<ResourceManagerService> mService;
sp<IResourceManagerClient> mTestClient1;
sp<IResourceManagerClient> mTestClient2;
@@ -512,10 +733,18 @@
addResource();
}
+TEST_F(ResourceManagerServiceTest, combineResource) {
+ testCombineResource();
+}
+
TEST_F(ResourceManagerServiceTest, removeResource) {
testRemoveResource();
}
+TEST_F(ResourceManagerServiceTest, removeClient) {
+ testRemoveClient();
+}
+
TEST_F(ResourceManagerServiceTest, reclaimResource) {
testReclaimResourceSecure();
testReclaimResourceNonSecure();
@@ -541,4 +770,12 @@
testIsCallingPriorityHigher();
}
+TEST_F(ResourceManagerServiceTest, testBatteryStats) {
+ testBatteryStats();
+}
+
+TEST_F(ResourceManagerServiceTest, testCpusetBoost) {
+ testCpusetBoost();
+}
+
} // namespace android